summaryrefslogtreecommitdiffstats
path: root/nikola/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'nikola/plugins')
-rw-r--r--nikola/plugins/basic_import.py1
-rw-r--r--nikola/plugins/command/auto.plugin2
-rw-r--r--nikola/plugins/command/auto/__init__.py23
-rw-r--r--nikola/plugins/command/bootswatch_theme.plugin2
-rw-r--r--nikola/plugins/command/bootswatch_theme.py9
-rw-r--r--nikola/plugins/command/check.plugin2
-rw-r--r--nikola/plugins/command/check.py112
-rw-r--r--nikola/plugins/command/console.plugin2
-rw-r--r--nikola/plugins/command/console.py1
-rw-r--r--nikola/plugins/command/deploy.plugin2
-rw-r--r--nikola/plugins/command/deploy.py1
-rw-r--r--nikola/plugins/command/github_deploy.plugin2
-rw-r--r--nikola/plugins/command/github_deploy.py1
-rw-r--r--nikola/plugins/command/import_wordpress.plugin2
-rw-r--r--nikola/plugins/command/import_wordpress.py60
-rw-r--r--nikola/plugins/command/init.plugin2
-rw-r--r--nikola/plugins/command/init.py11
-rw-r--r--nikola/plugins/command/install_theme.plugin2
-rw-r--r--nikola/plugins/command/install_theme.py1
-rw-r--r--nikola/plugins/command/new_page.plugin2
-rw-r--r--nikola/plugins/command/new_page.py1
-rw-r--r--nikola/plugins/command/new_post.plugin2
-rw-r--r--nikola/plugins/command/new_post.py1
-rw-r--r--nikola/plugins/command/orphans.plugin2
-rw-r--r--nikola/plugins/command/orphans.py1
-rw-r--r--nikola/plugins/command/plugin.plugin2
-rw-r--r--nikola/plugins/command/plugin.py1
-rw-r--r--nikola/plugins/command/rst2html.plugin2
-rw-r--r--nikola/plugins/command/rst2html/__init__.py3
-rw-r--r--nikola/plugins/command/serve.plugin2
-rw-r--r--nikola/plugins/command/serve.py14
-rw-r--r--nikola/plugins/command/status.py1
-rw-r--r--nikola/plugins/command/version.plugin2
-rw-r--r--nikola/plugins/command/version.py1
-rw-r--r--nikola/plugins/compile/html.plugin2
-rw-r--r--nikola/plugins/compile/html.py1
-rw-r--r--nikola/plugins/compile/ipynb.py1
-rw-r--r--nikola/plugins/compile/markdown.plugin2
-rw-r--r--nikola/plugins/compile/markdown/__init__.py1
-rw-r--r--nikola/plugins/compile/markdown/mdx_gist.plugin2
-rw-r--r--nikola/plugins/compile/markdown/mdx_gist.py5
-rw-r--r--nikola/plugins/compile/markdown/mdx_nikola.plugin2
-rw-r--r--nikola/plugins/compile/markdown/mdx_nikola.py27
-rw-r--r--nikola/plugins/compile/markdown/mdx_podcast.plugin2
-rw-r--r--nikola/plugins/compile/markdown/mdx_podcast.py6
-rw-r--r--nikola/plugins/compile/pandoc.plugin2
-rw-r--r--nikola/plugins/compile/pandoc.py1
-rw-r--r--nikola/plugins/compile/php.plugin2
-rw-r--r--nikola/plugins/compile/php.py1
-rw-r--r--nikola/plugins/compile/rest.plugin2
-rw-r--r--nikola/plugins/compile/rest/__init__.py4
-rw-r--r--nikola/plugins/compile/rest/chart.plugin2
-rw-r--r--nikola/plugins/compile/rest/chart.py14
-rw-r--r--nikola/plugins/compile/rest/doc.plugin2
-rw-r--r--nikola/plugins/compile/rest/doc.py1
-rw-r--r--nikola/plugins/compile/rest/gist.plugin2
-rw-r--r--nikola/plugins/compile/rest/gist.py2
-rw-r--r--nikola/plugins/compile/rest/listing.plugin2
-rw-r--r--nikola/plugins/compile/rest/listing.py11
-rw-r--r--nikola/plugins/compile/rest/media.plugin2
-rw-r--r--nikola/plugins/compile/rest/media.py2
-rw-r--r--nikola/plugins/compile/rest/post_list.plugin2
-rw-r--r--nikola/plugins/compile/rest/post_list.py6
-rw-r--r--nikola/plugins/compile/rest/slides.plugin2
-rw-r--r--nikola/plugins/compile/rest/slides.py2
-rw-r--r--nikola/plugins/compile/rest/soundcloud.plugin2
-rw-r--r--nikola/plugins/compile/rest/soundcloud.py3
-rw-r--r--nikola/plugins/compile/rest/thumbnail.plugin2
-rw-r--r--nikola/plugins/compile/rest/thumbnail.py8
-rw-r--r--nikola/plugins/compile/rest/vimeo.py2
-rw-r--r--nikola/plugins/compile/rest/youtube.py2
-rw-r--r--nikola/plugins/misc/scan_posts.plugin2
-rw-r--r--nikola/plugins/misc/scan_posts.py1
-rw-r--r--nikola/plugins/task/archive.plugin2
-rw-r--r--nikola/plugins/task/archive.py23
-rw-r--r--nikola/plugins/task/authors.plugin10
-rw-r--r--nikola/plugins/task/authors.py316
-rw-r--r--nikola/plugins/task/bundles.plugin2
-rw-r--r--nikola/plugins/task/bundles.py8
-rw-r--r--nikola/plugins/task/copy_assets.plugin2
-rw-r--r--nikola/plugins/task/copy_assets.py10
-rw-r--r--nikola/plugins/task/copy_files.plugin2
-rw-r--r--nikola/plugins/task/copy_files.py1
-rw-r--r--nikola/plugins/task/galleries.plugin2
-rw-r--r--nikola/plugins/task/galleries.py43
-rw-r--r--nikola/plugins/task/gzip.plugin2
-rw-r--r--nikola/plugins/task/gzip.py1
-rw-r--r--nikola/plugins/task/indexes.plugin2
-rw-r--r--nikola/plugins/task/indexes.py158
-rw-r--r--nikola/plugins/task/listings.plugin2
-rw-r--r--nikola/plugins/task/listings.py21
-rw-r--r--nikola/plugins/task/pages.plugin2
-rw-r--r--nikola/plugins/task/pages.py1
-rw-r--r--nikola/plugins/task/posts.plugin2
-rw-r--r--nikola/plugins/task/posts.py5
-rw-r--r--nikola/plugins/task/py3_switch.plugin13
-rw-r--r--nikola/plugins/task/py3_switch.py103
-rw-r--r--nikola/plugins/task/redirect.plugin2
-rw-r--r--nikola/plugins/task/redirect.py1
-rw-r--r--nikola/plugins/task/robots.plugin2
-rw-r--r--nikola/plugins/task/robots.py8
-rw-r--r--nikola/plugins/task/rss.plugin2
-rw-r--r--nikola/plugins/task/rss.py21
-rw-r--r--nikola/plugins/task/scale_images.plugin2
-rw-r--r--nikola/plugins/task/scale_images.py1
-rw-r--r--nikola/plugins/task/sitemap.plugin2
-rw-r--r--nikola/plugins/task/sitemap/__init__.py27
-rw-r--r--nikola/plugins/task/sources.plugin2
-rw-r--r--nikola/plugins/task/sources.py1
-rw-r--r--nikola/plugins/task/tags.plugin2
-rw-r--r--nikola/plugins/task/tags.py136
-rw-r--r--nikola/plugins/template/jinja.plugin2
-rw-r--r--nikola/plugins/template/jinja.py1
-rw-r--r--nikola/plugins/template/mako.plugin2
-rw-r--r--nikola/plugins/template/mako.py1
115 files changed, 1073 insertions, 287 deletions
diff --git a/nikola/plugins/basic_import.py b/nikola/plugins/basic_import.py
index 073a539..04f1091 100644
--- a/nikola/plugins/basic_import.py
+++ b/nikola/plugins/basic_import.py
@@ -48,7 +48,6 @@ links = {}
class ImportMixin(object):
-
"""Mixin with common used methods."""
name = "import_mixin"
diff --git a/nikola/plugins/command/auto.plugin b/nikola/plugins/command/auto.plugin
index 3e2b17d..1081c78 100644
--- a/nikola/plugins/command/auto.plugin
+++ b/nikola/plugins/command/auto.plugin
@@ -5,7 +5,7 @@ module = auto
[Documentation]
author = Roberto Alsina
version = 2.1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Automatically detect site changes, rebuild and optionally refresh a browser.
[Nikola]
diff --git a/nikola/plugins/command/auto/__init__.py b/nikola/plugins/command/auto/__init__.py
index 71f9624..e339c06 100644
--- a/nikola/plugins/command/auto/__init__.py
+++ b/nikola/plugins/command/auto/__init__.py
@@ -63,7 +63,7 @@ except ImportError:
from nikola.plugin_categories import Command
-from nikola.utils import req_missing, get_logger, get_theme_path, STDERR_HANDLER
+from nikola.utils import dns_sd, req_missing, get_logger, get_theme_path, STDERR_HANDLER
LRJS_PATH = os.path.join(os.path.dirname(__file__), 'livereload.js')
error_signal = signal('error')
refresh_signal = signal('refresh')
@@ -79,13 +79,14 @@ ERROR {}
class CommandAuto(Command):
-
"""Automatic rebuilds for Nikola."""
name = "auto"
logger = None
has_server = True
doc_purpose = "builds and serves a site; automatically detects site changes, rebuilds, and optionally refreshes a browser"
+ dns_sd = None
+
cmd_options = [
{
'name': 'port',
@@ -156,7 +157,7 @@ class CommandAuto(Command):
# Do not duplicate entries -- otherwise, multiple rebuilds are triggered
watched = set([
- 'templates/',
+ 'templates/', 'plugins/',
] + [get_theme_path(name) for name in self.site.THEMES])
for item in self.site.config['post_pages']:
watched.add(os.path.dirname(item[0]))
@@ -208,7 +209,6 @@ class CommandAuto(Command):
parent = self
class Mixed(WebSocketWSGIApplication):
-
"""A class that supports WS and HTTP protocols on the same port."""
def __call__(self, environ, start_response):
@@ -235,9 +235,12 @@ class CommandAuto(Command):
webbrowser.open('http://{0}:{1}'.format(host, port))
try:
+ self.dns_sd = dns_sd(port, (options['ipv6'] or '::' in host))
ws.serve_forever()
except KeyboardInterrupt:
self.logger.info("Server is shutting down.")
+ if self.dns_sd:
+ self.dns_sd.Reset()
# This is a hack, but something is locking up in a futex
# and exit() doesn't work.
os.kill(os.getpid(), 15)
@@ -262,6 +265,8 @@ class CommandAuto(Command):
fname = os.path.basename(event_path)
if (fname.endswith('~') or
fname.startswith('.') or
+ '__pycache__' in event_path or
+ event_path.endswith(('.pyc', '.pyo', '.pyd')) or
os.path.isdir(event_path)): # Skip on folders, these are usually duplicates
return
self.logger.info('REBUILDING SITE (from {0})'.format(event_path))
@@ -300,11 +305,14 @@ class CommandAuto(Command):
mimetype = 'text/html'
if p_uri.path == '/robots.txt':
- start_response('200 OK', [('Content-type', 'text/plain')])
+ start_response('200 OK', [('Content-type', 'text/plain; charset=UTF-8')])
return ['User-Agent: *\nDisallow: /\n'.encode('utf-8')]
elif os.path.isfile(f_path):
with open(f_path, 'rb') as fd:
- start_response('200 OK', [('Content-type', mimetype)])
+ if mimetype.startswith('text/') or mimetype.endswith('+xml'):
+ start_response('200 OK', [('Content-type', "{0}; charset=UTF-8".format(mimetype))])
+ else:
+ start_response('200 OK', [('Content-type', mimetype)])
return [self.file_filter(mimetype, fd.read())]
elif p_uri.path == '/livereload.js':
with open(LRJS_PATH, 'rb') as fd:
@@ -337,7 +345,6 @@ pending = []
class LRSocket(WebSocket):
-
"""Speak Livereload protocol."""
def __init__(self, *a, **kw):
@@ -410,7 +417,6 @@ class LRSocket(WebSocket):
class OurWatchHandler(FileSystemEventHandler):
-
"""A Nikola-specific handler for Watchdog."""
def __init__(self, function):
@@ -424,7 +430,6 @@ class OurWatchHandler(FileSystemEventHandler):
class ConfigWatchHandler(FileSystemEventHandler):
-
"""A Nikola-specific handler for Watchdog that handles the config file (as a workaround)."""
def __init__(self, configuration_filename, function):
diff --git a/nikola/plugins/command/bootswatch_theme.plugin b/nikola/plugins/command/bootswatch_theme.plugin
index fc25045..51e6718 100644
--- a/nikola/plugins/command/bootswatch_theme.plugin
+++ b/nikola/plugins/command/bootswatch_theme.plugin
@@ -5,7 +5,7 @@ module = bootswatch_theme
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Given a swatch name and a parent theme, creates a custom theme.
[Nikola]
diff --git a/nikola/plugins/command/bootswatch_theme.py b/nikola/plugins/command/bootswatch_theme.py
index b5644a1..afd15af 100644
--- a/nikola/plugins/command/bootswatch_theme.py
+++ b/nikola/plugins/command/bootswatch_theme.py
@@ -37,7 +37,6 @@ LOGGER = utils.get_logger('bootswatch_theme', utils.STDERR_HANDLER)
class CommandBootswatchTheme(Command):
-
"""Given a swatch name from bootswatch.com and a parent theme, creates a custom theme."""
name = "bootswatch_theme"
@@ -91,12 +90,16 @@ class CommandBootswatchTheme(Command):
LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent))
utils.makedirs(os.path.join('themes', name, 'assets', 'css'))
for fname in ('bootstrap.min.css', 'bootstrap.css'):
- url = 'http://bootswatch.com'
+ url = 'https://bootswatch.com'
if version:
url += '/' + version
url = '/'.join((url, swatch, fname))
LOGGER.info("Downloading: " + url)
- data = requests.get(url).text
+ r = requests.get(url)
+ if r.status_code > 299:
+ LOGGER.error('Error {} getting {}', r.status_code, url)
+ exit(1)
+ data = r.text
with open(os.path.join('themes', name, 'assets', 'css', fname),
'wb+') as output:
output.write(data.encode('utf-8'))
diff --git a/nikola/plugins/command/check.plugin b/nikola/plugins/command/check.plugin
index e380e64..6d2df82 100644
--- a/nikola/plugins/command/check.plugin
+++ b/nikola/plugins/command/check.plugin
@@ -5,7 +5,7 @@ module = check
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Check the generated site
[Nikola]
diff --git a/nikola/plugins/command/check.py b/nikola/plugins/command/check.py
index abf183e..bfc6ee2 100644
--- a/nikola/plugins/command/check.py
+++ b/nikola/plugins/command/check.py
@@ -46,7 +46,10 @@ from nikola.plugin_categories import Command
from nikola.utils import get_logger, STDERR_HANDLER
-def _call_nikola_list(site):
+def _call_nikola_list(site, cache=None):
+ if cache is not None:
+ if 'files' in cache and 'deps' in cache:
+ return cache['files'], cache['deps']
files = []
deps = defaultdict(list)
for task in generate_tasks('render_site', site.gen_tasks('render_site', "Task", '')):
@@ -57,16 +60,19 @@ def _call_nikola_list(site):
files.extend(task.targets)
for target in task.targets:
deps[target].extend(task.file_dep)
+ if cache is not None:
+ cache['files'] = files
+ cache['deps'] = deps
return files, deps
-def real_scan_files(site):
+def real_scan_files(site, cache=None):
"""Scan for files."""
task_fnames = set([])
real_fnames = set([])
output_folder = site.config['OUTPUT_FOLDER']
# First check that all targets are generated in the right places
- for fname in _call_nikola_list(site)[0]:
+ for fname in _call_nikola_list(site, cache)[0]:
fname = fname.strip()
if fname.startswith(output_folder):
task_fnames.add(fname)
@@ -94,7 +100,6 @@ def fs_relpath_from_url_path(url_path):
class CommandCheck(Command):
-
"""Check the generated site."""
name = "check"
@@ -162,22 +167,25 @@ class CommandCheck(Command):
self.logger.level = 1
else:
self.logger.level = 4
+ failure = False
if options['links']:
- failure = self.scan_links(options['find_sources'], options['remote'])
+ failure |= self.scan_links(options['find_sources'], options['remote'])
if options['files']:
- failure = self.scan_files()
+ failure |= self.scan_files()
if options['clean']:
- failure = self.clean_files()
+ failure |= self.clean_files()
if failure:
return 1
existing_targets = set([])
checked_remote_targets = {}
+ cache = {}
def analyze(self, fname, find_sources=False, check_remote=False):
"""Analyze links on a page."""
rv = False
self.whitelist = [re.compile(x) for x in self.site.config['LINK_CHECK_WHITELIST']]
+ self.internal_redirects = [urljoin('/', _[0]) for _ in self.site.config['REDIRECTIONS']]
base_url = urlparse(self.site.config['BASE_URL'])
self.existing_targets.add(self.site.config['SITE_URL'])
self.existing_targets.add(self.site.config['BASE_URL'])
@@ -185,7 +193,7 @@ class CommandCheck(Command):
deps = {}
if find_sources:
- deps = _call_nikola_list(self.site)[1]
+ deps = _call_nikola_list(self.site, self.cache)[1]
if url_type in ('absolute', 'full_path'):
url_netloc_to_root = urlparse(self.site.config['BASE_URL']).path
@@ -203,31 +211,70 @@ class CommandCheck(Command):
# Quietly ignore files that don’t exist; use `nikola check -f` instead (Issue #1831)
return False
- d = lxml.html.fromstring(open(filename, 'rb').read())
- for l in d.iterlinks():
+ if '.html' == fname[-5:]:
+ d = lxml.html.fromstring(open(filename, 'rb').read())
+ extra_objs = lxml.html.fromstring('<html/>')
+
+ # Turn elements with a srcset attribute into individual img elements with src attributes
+ for obj in list(d.xpath('(*//img|*//source)')):
+ if 'srcset' in obj.attrib:
+ for srcset_item in obj.attrib['srcset'].split(','):
+ extra_objs.append(lxml.etree.Element('img', src=srcset_item.strip().split(' ')[0]))
+ link_elements = list(d.iterlinks()) + list(extra_objs.iterlinks())
+ # Extract links from XML formats to minimal HTML, allowing those to go through the link checks
+ elif '.atom' == filename[-5:]:
+ d = lxml.etree.parse(filename)
+ link_elements = lxml.html.fromstring('<html/>')
+ for elm in d.findall('*//{http://www.w3.org/2005/Atom}link'):
+ feed_link = elm.attrib['href'].split('?')[0].strip() # strip FEED_LINKS_APPEND_QUERY
+ link_elements.append(lxml.etree.Element('a', href=feed_link))
+ link_elements = list(link_elements.iterlinks())
+ elif filename.endswith('sitemap.xml') or filename.endswith('sitemapindex.xml'):
+ d = lxml.etree.parse(filename)
+ link_elements = lxml.html.fromstring('<html/>')
+ for elm in d.getroot().findall("*//{http://www.sitemaps.org/schemas/sitemap/0.9}loc"):
+ link_elements.append(lxml.etree.Element('a', href=elm.text.strip()))
+ link_elements = list(link_elements.iterlinks())
+ else: # unsupported file type
+ return False
+
+ for l in link_elements:
target = l[2]
if target == "#":
continue
- target, _ = urldefrag(target)
+ target = urldefrag(target)[0]
+
+ if any([urlparse(target).netloc.endswith(_) for _ in ['example.com', 'example.net', 'example.org']]):
+ self.logger.info("Not testing example address \"{0}\".".format(target))
+ continue
+
+ # absolute URL to root-relative
+ if target.startswith(base_url.geturl()):
+ target = target.replace(base_url.geturl(), '/')
+
parsed = urlparse(target)
# Warn about links from https to http (mixed-security)
if base_url.netloc == parsed.netloc and base_url.scheme == "https" and parsed.scheme == "http":
self.logger.warn("Mixed-content security for link in {0}: {1}".format(filename, target))
+ # Link to an internal REDIRECTIONS page
+ if target in self.internal_redirects:
+ redir_status_code = 301
+ redir_target = [_dest for _target, _dest in self.site.config['REDIRECTIONS'] if urljoin('/', _target) == target][0]
+ self.logger.warn("Remote link moved PERMANENTLY to \"{0}\" and should be updated in {1}: {2} [HTTP: 301]".format(redir_target, filename, target))
+
# Absolute links to other domains, skip
# Absolute links when using only paths, skip.
if ((parsed.scheme or target.startswith('//')) and parsed.netloc != base_url.netloc) or \
((parsed.scheme or target.startswith('//')) and url_type in ('rel_path', 'full_path')):
if not check_remote or parsed.scheme not in ["http", "https"]:
continue
- if parsed.netloc == base_url.netloc: # absolute URL to self.site
- continue
if target in self.checked_remote_targets: # already checked this exact target
- if self.checked_remote_targets[target] in [301, 307]:
+ if self.checked_remote_targets[target] in [301, 308]:
self.logger.warn("Remote link PERMANENTLY redirected in {0}: {1} [Error {2}]".format(filename, target, self.checked_remote_targets[target]))
- elif self.checked_remote_targets[target] in [302, 308]:
- self.logger.info("Remote link temporarily redirected in {1}: {2} [HTTP: {3}]".format(filename, target, self.checked_remote_targets[target]))
+ elif self.checked_remote_targets[target] in [302, 307]:
+ self.logger.notice("Remote link temporarily redirected in {1}: {2} [HTTP: {3}]".format(filename, target, self.checked_remote_targets[target]))
elif self.checked_remote_targets[target] > 399:
self.logger.error("Broken link in {0}: {1} [Error {2}]".format(filename, target, self.checked_remote_targets[target]))
continue
@@ -255,7 +302,7 @@ class CommandCheck(Command):
if redir_status_code in [301, 308]:
self.logger.warn("Remote link moved PERMANENTLY to \"{0}\" and should be updated in {1}: {2} [HTTP: {3}]".format(resp.url, filename, target, redir_status_code))
if redir_status_code in [302, 307]:
- self.logger.info("Remote link temporarily redirected to \"{0}\" in {1}: {2} [HTTP: {3}]".format(resp.url, filename, target, redir_status_code))
+ self.logger.notice("Remote link temporarily redirected to \"{0}\" in {1}: {2} [HTTP: {3}]".format(resp.url, filename, target, redir_status_code))
self.checked_remote_targets[resp.url] = resp.status_code
self.checked_remote_targets[target] = redir_status_code
else:
@@ -275,8 +322,9 @@ class CommandCheck(Command):
target_filename = os.path.abspath(
os.path.join(self.site.config['OUTPUT_FOLDER'], unquote(target.lstrip('/'))))
else: # Relative path
+ unquoted_target = unquote(target).encode('utf-8') if sys.version_info.major >= 3 else unquote(target).decode('utf-8')
target_filename = os.path.abspath(
- os.path.join(os.path.dirname(filename), unquote(target)))
+ os.path.join(os.path.dirname(filename).encode('utf-8'), unquoted_target))
elif url_type in ('full_path', 'absolute'):
if url_type == 'absolute':
@@ -292,9 +340,10 @@ class CommandCheck(Command):
if any(re.search(x, target_filename) for x in self.whitelist):
continue
+
elif target_filename not in self.existing_targets:
if os.path.exists(target_filename):
- self.logger.notice("Good link {0} => {1}".format(target, target_filename))
+ self.logger.info(u"Good link {0} => {1}".format(target, target_filename))
self.existing_targets.add(target_filename)
else:
rv = True
@@ -304,7 +353,7 @@ class CommandCheck(Command):
self.logger.warn("\n".join(deps[filename]))
self.logger.warn("===============================\n")
except Exception as exc:
- self.logger.error("Error with: {0} {1}".format(filename, exc))
+ self.logger.error(u"Error with: {0} {1}".format(filename, exc))
return rv
def scan_links(self, find_sources=False, check_remote=False):
@@ -315,10 +364,21 @@ class CommandCheck(Command):
failure = False
# Maybe we should just examine all HTML files
output_folder = self.site.config['OUTPUT_FOLDER']
- for fname in _call_nikola_list(self.site)[0]:
- if fname.startswith(output_folder) and '.html' == fname[-5:]:
- if self.analyze(fname, find_sources, check_remote):
- failure = True
+
+ if urlparse(self.site.config['BASE_URL']).netloc == 'example.com':
+ self.logger.error("You've not changed the SITE_URL (or BASE_URL) setting from \"example.com\"!")
+
+ for fname in _call_nikola_list(self.site, self.cache)[0]:
+ if fname.startswith(output_folder):
+ if '.html' == fname[-5:]:
+ if self.analyze(fname, find_sources, check_remote):
+ failure = True
+ if '.atom' == fname[-5:]:
+ if self.analyze(fname, find_sources, False):
+ failure = True
+ if fname.endswith('sitemap.xml') or fname.endswith('sitemapindex.xml'):
+ if self.analyze(fname, find_sources, False):
+ failure = True
if not failure:
self.logger.info("All links checked.")
return failure
@@ -328,7 +388,7 @@ class CommandCheck(Command):
failure = False
self.logger.info("Checking Files:")
self.logger.info("===============\n")
- only_on_output, only_on_input = real_scan_files(self.site)
+ only_on_output, only_on_input = real_scan_files(self.site, self.cache)
# Ignore folders
only_on_output = [p for p in only_on_output if not os.path.isdir(p)]
@@ -351,7 +411,7 @@ class CommandCheck(Command):
def clean_files(self):
"""Remove orphaned files."""
- only_on_output, _ = real_scan_files(self.site)
+ only_on_output, _ = real_scan_files(self.site, self.cache)
for f in only_on_output:
self.logger.info('removed: {0}'.format(f))
os.unlink(f)
diff --git a/nikola/plugins/command/console.plugin b/nikola/plugins/command/console.plugin
index 333762c..9bcc909 100644
--- a/nikola/plugins/command/console.plugin
+++ b/nikola/plugins/command/console.plugin
@@ -5,7 +5,7 @@ module = console
[Documentation]
author = Chris Warrick, Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Start a debugging python console
[Nikola]
diff --git a/nikola/plugins/command/console.py b/nikola/plugins/command/console.py
index 539fa08..3d3daab 100644
--- a/nikola/plugins/command/console.py
+++ b/nikola/plugins/command/console.py
@@ -38,7 +38,6 @@ LOGGER = get_logger('console', STDERR_HANDLER)
class CommandConsole(Command):
-
"""Start debugging console."""
name = "console"
diff --git a/nikola/plugins/command/deploy.plugin b/nikola/plugins/command/deploy.plugin
index 4743ca2..8bdc0e2 100644
--- a/nikola/plugins/command/deploy.plugin
+++ b/nikola/plugins/command/deploy.plugin
@@ -5,7 +5,7 @@ module = deploy
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Deploy the site
[Nikola]
diff --git a/nikola/plugins/command/deploy.py b/nikola/plugins/command/deploy.py
index 821ea11..757c0d2 100644
--- a/nikola/plugins/command/deploy.py
+++ b/nikola/plugins/command/deploy.py
@@ -41,7 +41,6 @@ from nikola.utils import get_logger, remove_file, unicode_str, makedirs, STDERR_
class CommandDeploy(Command):
-
"""Deploy site."""
name = "deploy"
diff --git a/nikola/plugins/command/github_deploy.plugin b/nikola/plugins/command/github_deploy.plugin
index e793548..21e246c 100644
--- a/nikola/plugins/command/github_deploy.plugin
+++ b/nikola/plugins/command/github_deploy.plugin
@@ -5,7 +5,7 @@ module = github_deploy
[Documentation]
author = Puneeth Chaganti
version = 1,0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Deploy the site to GitHub pages.
[Nikola]
diff --git a/nikola/plugins/command/github_deploy.py b/nikola/plugins/command/github_deploy.py
index 0ab9332..2fe0d4e 100644
--- a/nikola/plugins/command/github_deploy.py
+++ b/nikola/plugins/command/github_deploy.py
@@ -57,7 +57,6 @@ def check_ghp_import_installed():
class CommandGitHubDeploy(Command):
-
"""Deploy site to GitHub Pages."""
name = 'github_deploy'
diff --git a/nikola/plugins/command/import_wordpress.plugin b/nikola/plugins/command/import_wordpress.plugin
index 6c4384e..eab9d17 100644
--- a/nikola/plugins/command/import_wordpress.plugin
+++ b/nikola/plugins/command/import_wordpress.plugin
@@ -5,7 +5,7 @@ module = import_wordpress
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Import a wordpress site from a XML dump (requires markdown).
[Nikola]
diff --git a/nikola/plugins/command/import_wordpress.py b/nikola/plugins/command/import_wordpress.py
index a652ec8..69ef144 100644
--- a/nikola/plugins/command/import_wordpress.py
+++ b/nikola/plugins/command/import_wordpress.py
@@ -50,7 +50,7 @@ except ImportError:
from nikola.plugin_categories import Command
from nikola import utils
-from nikola.utils import req_missing
+from nikola.utils import req_missing, unicode_str
from nikola.plugins.basic_import import ImportMixin, links
from nikola.nikola import DEFAULT_TRANSLATIONS_PATTERN
from nikola.plugins.command.init import SAMPLE_CONF, prepare_config, format_default_translations_config
@@ -88,7 +88,6 @@ def install_plugin(site, plugin_name, output_dir=None, show_install_notes=False)
class CommandImportWordpress(Command, ImportMixin):
-
"""Import a WordPress dump."""
name = "import_wordpress"
@@ -191,6 +190,12 @@ class CommandImportWordpress(Command, ImportMixin):
'type': bool,
'help': "Automatically installs the WordPress page compiler (either locally or in the new site) if required by other options.\nWarning: the compiler is GPL software!",
},
+ {
+ 'name': 'tag_saniziting_strategy',
+ 'long': 'tag-saniziting-strategy',
+ 'default': 'first',
+ 'help': 'lower: Convert all tag and category names to lower case\nfirst: Keep first spelling of tag or category name',
+ },
]
all_tags = set([])
@@ -239,6 +244,8 @@ class CommandImportWordpress(Command, ImportMixin):
self.install_wordpress_compiler = options.get('install_wordpress_compiler', False)
self.wordpress_page_compiler = None
+ self.tag_saniziting_strategy = options.get('tag_saniziting_strategy', 'first')
+
self.auth = None
if options.get('download_auth') is not None:
username_password = options.get('download_auth')
@@ -337,7 +344,10 @@ class CommandImportWordpress(Command, ImportMixin):
# Add tag redirects
for tag in self.all_tags:
try:
- tag_str = tag.decode('utf8')
+ if isinstance(tag, utils.bytes_str):
+ tag_str = tag.decode('utf8', 'replace')
+ else:
+ tag_str = tag
except AttributeError:
tag_str = tag
tag = utils.slugify(tag_str)
@@ -604,7 +614,7 @@ class CommandImportWordpress(Command, ImportMixin):
def transform_code(self, content):
"""Transform code blocks."""
- # http://en.support.wordpress.com/code/posting-source-code/. There are
+ # https://en.support.wordpress.com/code/posting-source-code/. There are
# a ton of things not supported here. We only do a basic [code
# lang="x"] -> ```x translation, and remove quoted html entities (<,
# >, &, and ").
@@ -686,7 +696,7 @@ class CommandImportWordpress(Command, ImportMixin):
elif approved == 'spam' or approved == 'trash':
pass
else:
- LOGGER.warn("Unknown comment approved status: " + str(approved))
+ LOGGER.warn("Unknown comment approved status: {0}".format(approved))
parent = int(get_text_tag(comment, "{{{0}}}comment_parent".format(wordpress_namespace), 0))
if parent == 0:
parent = None
@@ -707,7 +717,7 @@ class CommandImportWordpress(Command, ImportMixin):
"""Write comment header line."""
if header_content is None:
return
- header_content = str(header_content).replace('\n', ' ')
+ header_content = unicode_str(header_content).replace('\n', ' ')
line = '.. ' + header_field + ': ' + header_content + '\n'
fd.write(line.encode('utf8'))
@@ -747,6 +757,24 @@ class CommandImportWordpress(Command, ImportMixin):
tags_cats = tags + categories
return tags_cats, other_meta
+ _tag_sanitize_map = {True: {}, False: {}}
+
+ def _sanitize(self, tag, is_category):
+ if self.tag_saniziting_strategy == 'lower':
+ return tag.lower()
+ if tag.lower() not in self._tag_sanitize_map[is_category]:
+ self._tag_sanitize_map[is_category][tag.lower()] = [tag]
+ return tag
+ previous = self._tag_sanitize_map[is_category][tag.lower()]
+ if self.tag_saniziting_strategy == 'first':
+ if tag != previous[0]:
+ LOGGER.warn("Changing spelling of {0} name '{1}' to {2}.".format('category' if is_category else 'tag', tag, previous[0]))
+ return previous[0]
+ else:
+ LOGGER.error("Unknown tag sanitizing strategy '{0}'!".format(self.tag_saniziting_strategy))
+ sys.exit(1)
+ return tag
+
def import_postpage_item(self, item, wordpress_namespace, out_folder=None, attachments=None):
"""Take an item from the feed and creates a post file."""
if out_folder is None:
@@ -760,7 +788,10 @@ class CommandImportWordpress(Command, ImportMixin):
path = unquote(parsed.path.strip('/'))
try:
- path = path.decode('utf8')
+ if isinstance(path, utils.bytes_str):
+ path = path.decode('utf8', 'replace')
+ else:
+ path = path
except AttributeError:
pass
@@ -831,15 +862,24 @@ class CommandImportWordpress(Command, ImportMixin):
type = tag.attrib['domain']
if text == 'Uncategorized' and type == 'category':
continue
- self.all_tags.add(text)
if type == 'category':
- categories.append(type)
+ categories.append(text)
else:
tags.append(text)
if '$latex' in content:
tags.append('mathjax')
+ for i, cat in enumerate(categories[:]):
+ cat = self._sanitize(cat, True)
+ categories[i] = cat
+ self.all_tags.add(cat)
+
+ for i, tag in enumerate(tags[:]):
+ tag = self._sanitize(tag, False)
+ tags[i] = tag
+ self.all_tags.add(tag)
+
# Find post format if it's there
post_format = 'wp'
format_tag = [x for x in item.findall('*//{%s}meta_key' % wordpress_namespace) if x.text == '_tc_post_format']
@@ -905,7 +945,7 @@ class CommandImportWordpress(Command, ImportMixin):
comments.append(comment)
for comment in comments:
- comment_filename = slug + "." + str(comment['id']) + ".wpcomment"
+ comment_filename = "{0}.{1}.wpcomment".format(slug, comment['id'])
self._write_comment(os.path.join(self.output_folder, out_folder, comment_filename), comment)
return (out_folder, slug)
diff --git a/nikola/plugins/command/init.plugin b/nikola/plugins/command/init.plugin
index a5404c4..a8b1523 100644
--- a/nikola/plugins/command/init.plugin
+++ b/nikola/plugins/command/init.plugin
@@ -5,7 +5,7 @@ module = init
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create a new site.
[Nikola]
diff --git a/nikola/plugins/command/init.py b/nikola/plugins/command/init.py
index 91ccdb4..2dbee43 100644
--- a/nikola/plugins/command/init.py
+++ b/nikola/plugins/command/init.py
@@ -41,7 +41,7 @@ from pkg_resources import resource_filename
import tarfile
import nikola
-from nikola.nikola import DEFAULT_TRANSLATIONS_PATTERN, DEFAULT_INDEX_READ_MORE_LINK, DEFAULT_RSS_READ_MORE_LINK, LEGAL_VALUES, urlsplit, urlunsplit
+from nikola.nikola import DEFAULT_TRANSLATIONS_PATTERN, DEFAULT_INDEX_READ_MORE_LINK, DEFAULT_FEED_READ_MORE_LINK, LEGAL_VALUES, urlsplit, urlunsplit
from nikola.plugin_categories import Command
from nikola.utils import ask, ask_yesno, get_logger, makedirs, STDERR_HANDLER, load_messages
from nikola.packages.tzlocal import get_localzone
@@ -71,7 +71,7 @@ SAMPLE_CONF = {
'CATEGORY_OUTPUT_FLAT_HIERARCHY': False,
'TRANSLATIONS_PATTERN': DEFAULT_TRANSLATIONS_PATTERN,
'INDEX_READ_MORE_LINK': DEFAULT_INDEX_READ_MORE_LINK,
- 'RSS_READ_MORE_LINK': DEFAULT_RSS_READ_MORE_LINK,
+ 'FEED_READ_MORE_LINK': DEFAULT_FEED_READ_MORE_LINK,
'POSTS': """(
("posts/*.rst", "posts", "post.tmpl"),
("posts/*.txt", "posts", "post.tmpl"),
@@ -210,17 +210,16 @@ def prepare_config(config):
"""Parse sample config with JSON."""
p = config.copy()
p.update({k: json.dumps(v, ensure_ascii=False) for k, v in p.items()
- if k not in ('POSTS', 'PAGES', 'COMPILERS', 'TRANSLATIONS', 'NAVIGATION_LINKS', '_SUPPORTED_LANGUAGES', '_SUPPORTED_COMMENT_SYSTEMS', 'INDEX_READ_MORE_LINK', 'RSS_READ_MORE_LINK')})
+ if k not in ('POSTS', 'PAGES', 'COMPILERS', 'TRANSLATIONS', 'NAVIGATION_LINKS', '_SUPPORTED_LANGUAGES', '_SUPPORTED_COMMENT_SYSTEMS', 'INDEX_READ_MORE_LINK', 'FEED_READ_MORE_LINK')})
# READ_MORE_LINKs require some special treatment.
p['INDEX_READ_MORE_LINK'] = "'" + p['INDEX_READ_MORE_LINK'].replace("'", "\\'") + "'"
- p['RSS_READ_MORE_LINK'] = "'" + p['RSS_READ_MORE_LINK'].replace("'", "\\'") + "'"
+ p['FEED_READ_MORE_LINK'] = "'" + p['FEED_READ_MORE_LINK'].replace("'", "\\'") + "'"
# fix booleans and None
p.update({k: str(v) for k, v in config.items() if isinstance(v, bool) or v is None})
return p
class CommandInit(Command):
-
"""Create a new site."""
name = "init"
@@ -358,7 +357,7 @@ class CommandInit(Command):
def tzhandler(default, toconf):
print("\nPlease choose the correct time zone for your blog. Nikola uses the tz database.")
print("You can find your time zone here:")
- print("http://en.wikipedia.org/wiki/List_of_tz_database_time_zones")
+ print("https://en.wikipedia.org/wiki/List_of_tz_database_time_zones")
print("")
answered = False
while not answered:
diff --git a/nikola/plugins/command/install_theme.plugin b/nikola/plugins/command/install_theme.plugin
index 8434f2e..aa68773 100644
--- a/nikola/plugins/command/install_theme.plugin
+++ b/nikola/plugins/command/install_theme.plugin
@@ -5,7 +5,7 @@ module = install_theme
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Install a theme into the current site.
[Nikola]
diff --git a/nikola/plugins/command/install_theme.py b/nikola/plugins/command/install_theme.py
index f02252e..bad335c 100644
--- a/nikola/plugins/command/install_theme.py
+++ b/nikola/plugins/command/install_theme.py
@@ -43,7 +43,6 @@ LOGGER = utils.get_logger('install_theme', utils.STDERR_HANDLER)
class CommandInstallTheme(Command):
-
"""Install a theme."""
name = "install_theme"
diff --git a/nikola/plugins/command/new_page.plugin b/nikola/plugins/command/new_page.plugin
index 145a419..3eaecb4 100644
--- a/nikola/plugins/command/new_page.plugin
+++ b/nikola/plugins/command/new_page.plugin
@@ -5,7 +5,7 @@ module = new_page
[Documentation]
author = Roberto Alsina, Chris Warrick
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create a new page.
[Nikola]
diff --git a/nikola/plugins/command/new_page.py b/nikola/plugins/command/new_page.py
index 811e28b..8843421 100644
--- a/nikola/plugins/command/new_page.py
+++ b/nikola/plugins/command/new_page.py
@@ -32,7 +32,6 @@ from nikola.plugin_categories import Command
class CommandNewPage(Command):
-
"""Create a new page."""
name = "new_page"
diff --git a/nikola/plugins/command/new_post.plugin b/nikola/plugins/command/new_post.plugin
index d88469f..e9c3af5 100644
--- a/nikola/plugins/command/new_post.plugin
+++ b/nikola/plugins/command/new_post.plugin
@@ -5,7 +5,7 @@ module = new_post
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create a new post.
[Nikola]
diff --git a/nikola/plugins/command/new_post.py b/nikola/plugins/command/new_post.py
index f9fe3ff..30d009d 100644
--- a/nikola/plugins/command/new_post.py
+++ b/nikola/plugins/command/new_post.py
@@ -114,7 +114,6 @@ def get_date(schedule=False, rule=None, last_date=None, tz=None, iso8601=False):
class CommandNewPost(Command):
-
"""Create a new post."""
name = "new_post"
diff --git a/nikola/plugins/command/orphans.plugin b/nikola/plugins/command/orphans.plugin
index 669429d..d20c539 100644
--- a/nikola/plugins/command/orphans.plugin
+++ b/nikola/plugins/command/orphans.plugin
@@ -5,7 +5,7 @@ module = orphans
[Documentation]
author = Roberto Alsina, Chris Warrick
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = List all orphans
[Nikola]
diff --git a/nikola/plugins/command/orphans.py b/nikola/plugins/command/orphans.py
index b12cc67..f061d39 100644
--- a/nikola/plugins/command/orphans.py
+++ b/nikola/plugins/command/orphans.py
@@ -34,7 +34,6 @@ from nikola.plugins.command.check import real_scan_files
class CommandOrphans(Command):
-
"""List all orphans."""
name = "orphans"
diff --git a/nikola/plugins/command/plugin.plugin b/nikola/plugins/command/plugin.plugin
index d44dcf3..016bcaa 100644
--- a/nikola/plugins/command/plugin.plugin
+++ b/nikola/plugins/command/plugin.plugin
@@ -5,7 +5,7 @@ module = plugin
[Documentation]
author = Roberto Alsina and Chris Warrick
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Manage Nikola plugins
[Nikola]
diff --git a/nikola/plugins/command/plugin.py b/nikola/plugins/command/plugin.py
index f892ee9..1df7b71 100644
--- a/nikola/plugins/command/plugin.py
+++ b/nikola/plugins/command/plugin.py
@@ -45,7 +45,6 @@ LOGGER = utils.get_logger('plugin', utils.STDERR_HANDLER)
class CommandPlugin(Command):
-
"""Manage plugins."""
json = None
diff --git a/nikola/plugins/command/rst2html.plugin b/nikola/plugins/command/rst2html.plugin
index 02c9276..a095705 100644
--- a/nikola/plugins/command/rst2html.plugin
+++ b/nikola/plugins/command/rst2html.plugin
@@ -5,7 +5,7 @@ module = rst2html
[Documentation]
author = Chris Warrick
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile reStructuredText to HTML using the Nikola architecture
[Nikola]
diff --git a/nikola/plugins/command/rst2html/__init__.py b/nikola/plugins/command/rst2html/__init__.py
index 06afffd..68ea13d 100644
--- a/nikola/plugins/command/rst2html/__init__.py
+++ b/nikola/plugins/command/rst2html/__init__.py
@@ -36,7 +36,6 @@ from nikola.plugin_categories import Command
class CommandRst2Html(Command):
-
"""Compile reStructuredText to HTML, using Nikola architecture."""
name = "rst2html"
@@ -65,7 +64,7 @@ class CommandRst2Html(Command):
parser = lxml.html.HTMLParser(remove_blank_text=True)
doc = lxml.html.document_fromstring(template_output, parser)
html = b'<!DOCTYPE html>\n' + lxml.html.tostring(doc, encoding='utf8', method='html', pretty_print=True)
- print(html)
+ print(html.decode('utf-8'))
if error_level < 3:
return 0
else:
diff --git a/nikola/plugins/command/serve.plugin b/nikola/plugins/command/serve.plugin
index aca71ec..a4a726f 100644
--- a/nikola/plugins/command/serve.plugin
+++ b/nikola/plugins/command/serve.plugin
@@ -5,7 +5,7 @@ module = serve
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Start test server.
[Nikola]
diff --git a/nikola/plugins/command/serve.py b/nikola/plugins/command/serve.py
index 0441c93..b647bb7 100644
--- a/nikola/plugins/command/serve.py
+++ b/nikola/plugins/command/serve.py
@@ -45,24 +45,23 @@ except ImportError:
from nikola.plugin_categories import Command
-from nikola.utils import get_logger, STDERR_HANDLER
+from nikola.utils import dns_sd, get_logger, STDERR_HANDLER
class IPv6Server(HTTPServer):
-
"""An IPv6 HTTPServer."""
address_family = socket.AF_INET6
class CommandServe(Command):
-
"""Start test server."""
name = "serve"
doc_usage = "[options]"
doc_purpose = "start the test webserver"
logger = None
+ dns_sd = None
cmd_options = (
{
@@ -152,14 +151,16 @@ class CommandServe(Command):
raise e
else:
try:
+ self.dns_sd = dns_sd(options['port'], (options['ipv6'] or '::' in options['address']))
httpd.serve_forever()
except KeyboardInterrupt:
self.logger.info("Server is shutting down.")
+ if self.dns_sd:
+ self.dns_sd.Reset()
return 130
class OurHTTPRequestHandler(SimpleHTTPRequestHandler):
-
"""A request handler, modified for Nikola."""
extensions_map = dict(SimpleHTTPRequestHandler.extensions_map)
@@ -242,7 +243,10 @@ class OurHTTPRequestHandler(SimpleHTTPRequestHandler):
f.seek(0)
self.send_response(200)
- self.send_header("Content-type", ctype)
+ if ctype.startswith('text/') or ctype.endswith('+xml'):
+ self.send_header("Content-Type", "{0}; charset=UTF-8".format(ctype))
+ else:
+ self.send_header("Content-Type", ctype)
if os.path.splitext(path)[1] == '.svgz':
# Special handling for svgz to make it work nice with browsers.
self.send_header("Content-Encoding", 'gzip')
diff --git a/nikola/plugins/command/status.py b/nikola/plugins/command/status.py
index 55e7f95..40f4f77 100644
--- a/nikola/plugins/command/status.py
+++ b/nikola/plugins/command/status.py
@@ -36,7 +36,6 @@ from nikola.plugin_categories import Command
class CommandStatus(Command):
-
"""Display site status."""
name = "status"
diff --git a/nikola/plugins/command/version.plugin b/nikola/plugins/command/version.plugin
index 4708bdb..d78b79b 100644
--- a/nikola/plugins/command/version.plugin
+++ b/nikola/plugins/command/version.plugin
@@ -5,7 +5,7 @@ module = version
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Show nikola version
[Nikola]
diff --git a/nikola/plugins/command/version.py b/nikola/plugins/command/version.py
index ad08f64..b83d622 100644
--- a/nikola/plugins/command/version.py
+++ b/nikola/plugins/command/version.py
@@ -38,7 +38,6 @@ URL = 'https://pypi.python.org/pypi?:action=doap&name=Nikola'
class CommandVersion(Command):
-
"""Print Nikola version."""
name = "version"
diff --git a/nikola/plugins/compile/html.plugin b/nikola/plugins/compile/html.plugin
index 53ade61..f95bdd5 100644
--- a/nikola/plugins/compile/html.plugin
+++ b/nikola/plugins/compile/html.plugin
@@ -5,7 +5,7 @@ module = html
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile HTML into HTML (just copy)
[Nikola]
diff --git a/nikola/plugins/compile/html.py b/nikola/plugins/compile/html.py
index 5f8b244..6ff5de8 100644
--- a/nikola/plugins/compile/html.py
+++ b/nikola/plugins/compile/html.py
@@ -36,7 +36,6 @@ from nikola.utils import makedirs, write_metadata
class CompileHtml(PageCompiler):
-
"""Compile HTML into HTML."""
name = "html"
diff --git a/nikola/plugins/compile/ipynb.py b/nikola/plugins/compile/ipynb.py
index a9dedde..1023b31 100644
--- a/nikola/plugins/compile/ipynb.py
+++ b/nikola/plugins/compile/ipynb.py
@@ -53,7 +53,6 @@ from nikola.utils import makedirs, req_missing, get_logger, STDERR_HANDLER
class CompileIPynb(PageCompiler):
-
"""Compile IPynb into HTML."""
name = "ipynb"
diff --git a/nikola/plugins/compile/markdown.plugin b/nikola/plugins/compile/markdown.plugin
index f7d11b1..2607413 100644
--- a/nikola/plugins/compile/markdown.plugin
+++ b/nikola/plugins/compile/markdown.plugin
@@ -5,7 +5,7 @@ module = markdown
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile Markdown into HTML
[Nikola]
diff --git a/nikola/plugins/compile/markdown/__init__.py b/nikola/plugins/compile/markdown/__init__.py
index c1425a1..93438a3 100644
--- a/nikola/plugins/compile/markdown/__init__.py
+++ b/nikola/plugins/compile/markdown/__init__.py
@@ -44,7 +44,6 @@ from nikola.utils import makedirs, req_missing, write_metadata
class CompileMarkdown(PageCompiler):
-
"""Compile Markdown into HTML."""
name = "markdown"
diff --git a/nikola/plugins/compile/markdown/mdx_gist.plugin b/nikola/plugins/compile/markdown/mdx_gist.plugin
index 7fe676c..85b5450 100644
--- a/nikola/plugins/compile/markdown/mdx_gist.plugin
+++ b/nikola/plugins/compile/markdown/mdx_gist.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Extension for embedding gists
diff --git a/nikola/plugins/compile/markdown/mdx_gist.py b/nikola/plugins/compile/markdown/mdx_gist.py
index f439fa2..a930de5 100644
--- a/nikola/plugins/compile/markdown/mdx_gist.py
+++ b/nikola/plugins/compile/markdown/mdx_gist.py
@@ -22,7 +22,7 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Warning: URL formats of "raw" gists are undocummented and subject to change.
-# See also: http://developer.github.com/v3/gists/
+# See also: https://developer.github.com/v3/gists/
#
# Inspired by "[Python] reStructuredText GitHub Gist directive"
# (https://gist.github.com/brianhsu/1407759), public domain by Brian Hsu
@@ -217,7 +217,6 @@ GIST_RST_RE = r'(?m)^\.\.\s*gist::\s*(?P<gist_id>[^\]\s]+)(?:\s*(?P<filename>.+?
class GistFetchException(Exception):
-
"""Raised when attempt to fetch content of a Gist from github.com fails."""
def __init__(self, url, status_code):
@@ -228,7 +227,6 @@ class GistFetchException(Exception):
class GistPattern(Pattern):
-
"""InlinePattern for footnote markers in a document's body text."""
def __init__(self, pattern, configs):
@@ -290,7 +288,6 @@ class GistPattern(Pattern):
class GistExtension(MarkdownExtension, Extension):
-
"""Gist extension for Markdown."""
def __init__(self, configs={}):
diff --git a/nikola/plugins/compile/markdown/mdx_nikola.plugin b/nikola/plugins/compile/markdown/mdx_nikola.plugin
index 12e4fb6..3c5c638 100644
--- a/nikola/plugins/compile/markdown/mdx_nikola.plugin
+++ b/nikola/plugins/compile/markdown/mdx_nikola.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Nikola-specific Markdown extensions
diff --git a/nikola/plugins/compile/markdown/mdx_nikola.py b/nikola/plugins/compile/markdown/mdx_nikola.py
index 54cc18c..7984121 100644
--- a/nikola/plugins/compile/markdown/mdx_nikola.py
+++ b/nikola/plugins/compile/markdown/mdx_nikola.py
@@ -24,25 +24,31 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-"""Markdown Extension for Nikola-specific post-processing."""
+"""Markdown Extension for Nikola.
+
+- Specific post-processing.
+- Strikethrough inline patterns.
+"""
from __future__ import unicode_literals
import re
try:
from markdown.postprocessors import Postprocessor
+ from markdown.inlinepatterns import SimpleTagPattern
from markdown.extensions import Extension
except ImportError:
# No need to catch this, if you try to use this without Markdown,
# the markdown compiler will fail first
- Postprocessor = Extension = object
+ Postprocessor = SimpleTagPattern = Extension = object
from nikola.plugin_categories import MarkdownExtension
+
CODERE = re.compile('<div class="codehilite"><pre>(.*?)</pre></div>', flags=re.MULTILINE | re.DOTALL)
+STRIKE_RE = r"(~{2})(.+?)(~{2})" # ~~strike~~
class NikolaPostProcessor(Postprocessor):
-
"""Nikola-specific post-processing for Markdown."""
def run(self, text):
@@ -57,13 +63,22 @@ class NikolaPostProcessor(Postprocessor):
class NikolaExtension(MarkdownExtension, Extension):
+ """Nikola Markdown extensions."""
- """Extension for injecting the postprocessor."""
-
- def extendMarkdown(self, md, md_globals):
+ def _add_nikola_post_processor(self, md):
"""Extend Markdown with the postprocessor."""
pp = NikolaPostProcessor()
md.postprocessors.add('nikola_post_processor', pp, '_end')
+
+ def _add_strikethrough_inline_pattern(self, md):
+ """Support PHP-Markdown style strikethrough, for example: ``~~strike~~``."""
+ pattern = SimpleTagPattern(STRIKE_RE, 'del')
+ md.inlinePatterns.add('strikethrough', pattern, '_end')
+
+ def extendMarkdown(self, md, md_globals):
+ """Extend markdown to Nikola flavours."""
+ self._add_nikola_post_processor(md)
+ self._add_strikethrough_inline_pattern(md)
md.registerExtension(self)
diff --git a/nikola/plugins/compile/markdown/mdx_podcast.plugin b/nikola/plugins/compile/markdown/mdx_podcast.plugin
index c92a8a0..c4ee7e9 100644
--- a/nikola/plugins/compile/markdown/mdx_podcast.plugin
+++ b/nikola/plugins/compile/markdown/mdx_podcast.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Markdown extensions for embedding podcasts and other audio files
diff --git a/nikola/plugins/compile/markdown/mdx_podcast.py b/nikola/plugins/compile/markdown/mdx_podcast.py
index 61afdbf..0f68e40 100644
--- a/nikola/plugins/compile/markdown/mdx_podcast.py
+++ b/nikola/plugins/compile/markdown/mdx_podcast.py
@@ -30,10 +30,10 @@ Extension to Python Markdown for Embedded Audio.
Basic Example:
>>> import markdown
->>> text = "[podcast]http://archive.org/download/Rebeldes_Stereotipos/rs20120609_1.mp3[/podcast]"
+>>> text = "[podcast]https://archive.org/download/Rebeldes_Stereotipos/rs20120609_1.mp3[/podcast]"
>>> html = markdown.markdown(text, [PodcastExtension()])
>>> print(html)
-<p><audio controls=""><source src="http://archive.org/download/Rebeldes_Stereotipos/rs20120609_1.mp3" type="audio/mpeg"></source></audio></p>
+<p><audio controls=""><source src="https://archive.org/download/Rebeldes_Stereotipos/rs20120609_1.mp3" type="audio/mpeg"></source></audio></p>
"""
from __future__ import print_function, unicode_literals
@@ -51,7 +51,6 @@ PODCAST_RE = r'\[podcast\](?P<url>.+)\[/podcast\]'
class PodcastPattern(Pattern):
-
"""InlinePattern for footnote markers in a document's body text."""
def __init__(self, pattern, configs):
@@ -70,7 +69,6 @@ class PodcastPattern(Pattern):
class PodcastExtension(MarkdownExtension, Extension):
-
""""Podcast extension for Markdown."""
def __init__(self, configs={}):
diff --git a/nikola/plugins/compile/pandoc.plugin b/nikola/plugins/compile/pandoc.plugin
index 3ff3668..2a69095 100644
--- a/nikola/plugins/compile/pandoc.plugin
+++ b/nikola/plugins/compile/pandoc.plugin
@@ -5,7 +5,7 @@ module = pandoc
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile markups into HTML using pandoc
[Nikola]
diff --git a/nikola/plugins/compile/pandoc.py b/nikola/plugins/compile/pandoc.py
index 3030626..85e84fc 100644
--- a/nikola/plugins/compile/pandoc.py
+++ b/nikola/plugins/compile/pandoc.py
@@ -40,7 +40,6 @@ from nikola.utils import req_missing, makedirs, write_metadata
class CompilePandoc(PageCompiler):
-
"""Compile markups into HTML using pandoc."""
name = "pandoc"
diff --git a/nikola/plugins/compile/php.plugin b/nikola/plugins/compile/php.plugin
index 151c022..f4fb0c1 100644
--- a/nikola/plugins/compile/php.plugin
+++ b/nikola/plugins/compile/php.plugin
@@ -5,7 +5,7 @@ module = php
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile PHP into HTML (just copy and name the file .php)
[Nikola]
diff --git a/nikola/plugins/compile/php.py b/nikola/plugins/compile/php.py
index 28f4923..a60e31a 100644
--- a/nikola/plugins/compile/php.py
+++ b/nikola/plugins/compile/php.py
@@ -37,7 +37,6 @@ from hashlib import md5
class CompilePhp(PageCompiler):
-
"""Compile PHP into PHP."""
name = "php"
diff --git a/nikola/plugins/compile/rest.plugin b/nikola/plugins/compile/rest.plugin
index cf842c7..4d9041a 100644
--- a/nikola/plugins/compile/rest.plugin
+++ b/nikola/plugins/compile/rest.plugin
@@ -5,7 +5,7 @@ module = rest
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile reSt into HTML
[Nikola]
diff --git a/nikola/plugins/compile/rest/__init__.py b/nikola/plugins/compile/rest/__init__.py
index b99e872..4b04958 100644
--- a/nikola/plugins/compile/rest/__init__.py
+++ b/nikola/plugins/compile/rest/__init__.py
@@ -42,7 +42,6 @@ from nikola.utils import unicode_str, get_logger, makedirs, write_metadata, STDE
class CompileRest(PageCompiler):
-
"""Compile reStructuredText into HTML."""
name = "rest"
@@ -172,7 +171,6 @@ def get_observer(settings):
class NikolaReader(docutils.readers.standalone.Reader):
-
"""Nikola-specific docutils reader."""
def __init__(self, *args, **kwargs):
@@ -196,7 +194,7 @@ def add_node(node, visit_function=None, depart_function=None):
"""Register a Docutils node class.
This function is completely optional. It is a same concept as
- `Sphinx add_node function <http://sphinx-doc.org/ext/appapi.html#sphinx.application.Sphinx.add_node>`_.
+ `Sphinx add_node function <http://sphinx-doc.org/extdev/appapi.html#sphinx.application.Sphinx.add_node>`_.
For example::
diff --git a/nikola/plugins/compile/rest/chart.plugin b/nikola/plugins/compile/rest/chart.plugin
index 438abe4..0a7896f 100644
--- a/nikola/plugins/compile/rest/chart.plugin
+++ b/nikola/plugins/compile/rest/chart.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Chart directive based in PyGal
diff --git a/nikola/plugins/compile/rest/chart.py b/nikola/plugins/compile/rest/chart.py
index 88fdff3..ed8a250 100644
--- a/nikola/plugins/compile/rest/chart.py
+++ b/nikola/plugins/compile/rest/chart.py
@@ -43,7 +43,6 @@ _site = None
class Plugin(RestExtension):
-
"""Plugin for chart role."""
name = "rest_chart"
@@ -57,7 +56,6 @@ class Plugin(RestExtension):
class Chart(Directive):
-
"""reStructuredText extension for inserting charts as SVG.
Usage:
@@ -150,15 +148,15 @@ class Chart(Directive):
style = getattr(pygal.style, style_name)
for k, v in self.options.items():
options[k] = literal_eval(v)
-
- chart = getattr(pygal, self.arguments[0])(style=style)
+ chart = pygal
+ for o in self.arguments[0].split('.'):
+ chart = getattr(chart, o)
+ chart = chart(style=style)
+ if _site and _site.invariant:
+ chart.no_prefix = True
chart.config(**options)
for line in self.content:
label, series = literal_eval('({0})'.format(line))
chart.add(label, series)
data = chart.render().decode('utf8')
- if _site and _site.invariant:
- import re
- data = re.sub('id="chart-[a-f0-9\-]+"', 'id="chart-foobar"', data)
- data = re.sub('#chart-[a-f0-9\-]+', '#chart-foobar', data)
return [nodes.raw('', data, format='html')]
diff --git a/nikola/plugins/compile/rest/doc.plugin b/nikola/plugins/compile/rest/doc.plugin
index facdd03..e447eb2 100644
--- a/nikola/plugins/compile/rest/doc.plugin
+++ b/nikola/plugins/compile/rest/doc.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Manuel Kaufmann
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Role to link another page / post from the blog
diff --git a/nikola/plugins/compile/rest/doc.py b/nikola/plugins/compile/rest/doc.py
index 99cce81..578f012 100644
--- a/nikola/plugins/compile/rest/doc.py
+++ b/nikola/plugins/compile/rest/doc.py
@@ -34,7 +34,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for doc role."""
name = 'rest_doc'
diff --git a/nikola/plugins/compile/rest/gist.plugin b/nikola/plugins/compile/rest/gist.plugin
index 9fa2e82..763c1d2 100644
--- a/nikola/plugins/compile/rest/gist.plugin
+++ b/nikola/plugins/compile/rest/gist.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Gist directive
diff --git a/nikola/plugins/compile/rest/gist.py b/nikola/plugins/compile/rest/gist.py
index 736ee37..e40c3b2 100644
--- a/nikola/plugins/compile/rest/gist.py
+++ b/nikola/plugins/compile/rest/gist.py
@@ -11,7 +11,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for gist directive."""
name = "rest_gist"
@@ -24,7 +23,6 @@ class Plugin(RestExtension):
class GitHubGist(Directive):
-
"""Embed GitHub Gist.
Usage:
diff --git a/nikola/plugins/compile/rest/listing.plugin b/nikola/plugins/compile/rest/listing.plugin
index 85c780f..3ebb296 100644
--- a/nikola/plugins/compile/rest/listing.plugin
+++ b/nikola/plugins/compile/rest/listing.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Extension for source listings
diff --git a/nikola/plugins/compile/rest/listing.py b/nikola/plugins/compile/rest/listing.py
index 4871bf3..07f1686 100644
--- a/nikola/plugins/compile/rest/listing.py
+++ b/nikola/plugins/compile/rest/listing.py
@@ -55,7 +55,6 @@ from nikola.plugin_categories import RestExtension
# A sanitized version of docutils.parsers.rst.directives.body.CodeBlock.
class CodeBlock(Directive):
-
"""Parse and mark up content of a code block."""
optional_arguments = 1
@@ -126,7 +125,6 @@ docutils.parsers.rst.directives.misc.CodeBlock = CodeBlock
class Plugin(RestExtension):
-
"""Plugin for listing directive."""
name = "rest_listing"
@@ -152,7 +150,6 @@ listing_spec['linenos'] = directives.unchanged
class Listing(Include):
-
"""Create a highlighted block of code from a file in listings/.
Usage:
@@ -171,7 +168,12 @@ class Listing(Include):
"""Run listing directive."""
_fname = self.arguments.pop(0)
fname = _fname.replace('/', os.sep)
- lang = self.arguments.pop(0)
+ try:
+ lang = self.arguments.pop(0)
+ self.options['code'] = lang
+ except IndexError:
+ self.options['literal'] = True
+
if len(self.folders) == 1:
listings_folder = next(iter(self.folders.keys()))
if fname.startswith(listings_folder):
@@ -181,7 +183,6 @@ class Listing(Include):
else:
fpath = os.path.join(fname) # must be new syntax: specify folder name
self.arguments.insert(0, fpath)
- self.options['code'] = lang
if 'linenos' in self.options:
self.options['number-lines'] = self.options['linenos']
with io.open(fpath, 'r+', encoding='utf8') as fileobject:
diff --git a/nikola/plugins/compile/rest/media.plugin b/nikola/plugins/compile/rest/media.plugin
index 9803c8f..8dfb19c 100644
--- a/nikola/plugins/compile/rest/media.plugin
+++ b/nikola/plugins/compile/rest/media.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Directive to support oembed via micawber
diff --git a/nikola/plugins/compile/rest/media.py b/nikola/plugins/compile/rest/media.py
index 345e331..d075e44 100644
--- a/nikola/plugins/compile/rest/media.py
+++ b/nikola/plugins/compile/rest/media.py
@@ -40,7 +40,6 @@ from nikola.utils import req_missing
class Plugin(RestExtension):
-
"""Plugin for reST media directive."""
name = "rest_media"
@@ -53,7 +52,6 @@ class Plugin(RestExtension):
class Media(Directive):
-
"""reST extension for inserting any sort of media using micawber."""
has_content = False
diff --git a/nikola/plugins/compile/rest/post_list.plugin b/nikola/plugins/compile/rest/post_list.plugin
index 48969bf..1802f2b 100644
--- a/nikola/plugins/compile/rest/post_list.plugin
+++ b/nikola/plugins/compile/rest/post_list.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Udo Spallek
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Includes a list of posts with tag and slide based filters.
diff --git a/nikola/plugins/compile/rest/post_list.py b/nikola/plugins/compile/rest/post_list.py
index a22ee85..df9376b 100644
--- a/nikola/plugins/compile/rest/post_list.py
+++ b/nikola/plugins/compile/rest/post_list.py
@@ -43,7 +43,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for reST post-list directive."""
name = "rest_post_list"
@@ -57,7 +56,6 @@ class Plugin(RestExtension):
class PostList(Directive):
-
"""Provide a reStructuredText directive to create a list of posts.
Post List
@@ -204,8 +202,10 @@ class PostList(Directive):
template_data = {
'lang': lang,
'posts': posts,
- 'date_format': self.site.GLOBAL_CONTEXT.get('date_format'),
+ # Need to provide str, not TranslatableSetting (Issue #2104)
+ 'date_format': self.site.GLOBAL_CONTEXT.get('date_format')[lang],
'post_list_id': post_list_id,
+ 'messages': self.site.MESSAGES,
}
output = self.site.template_system.render_template(
template, None, template_data)
diff --git a/nikola/plugins/compile/rest/slides.plugin b/nikola/plugins/compile/rest/slides.plugin
index 5c05b89..389da39 100644
--- a/nikola/plugins/compile/rest/slides.plugin
+++ b/nikola/plugins/compile/rest/slides.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Slides directive
diff --git a/nikola/plugins/compile/rest/slides.py b/nikola/plugins/compile/rest/slides.py
index 2522e55..eb2cc97 100644
--- a/nikola/plugins/compile/rest/slides.py
+++ b/nikola/plugins/compile/rest/slides.py
@@ -37,7 +37,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for reST slides directive."""
name = "rest_slides"
@@ -51,7 +50,6 @@ class Plugin(RestExtension):
class Slides(Directive):
-
"""reST extension for inserting slideshows."""
has_content = True
diff --git a/nikola/plugins/compile/rest/soundcloud.plugin b/nikola/plugins/compile/rest/soundcloud.plugin
index 75469e4..4e36ea4 100644
--- a/nikola/plugins/compile/rest/soundcloud.plugin
+++ b/nikola/plugins/compile/rest/soundcloud.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Soundcloud directive
diff --git a/nikola/plugins/compile/rest/soundcloud.py b/nikola/plugins/compile/rest/soundcloud.py
index 30134a9..2577ff1 100644
--- a/nikola/plugins/compile/rest/soundcloud.py
+++ b/nikola/plugins/compile/rest/soundcloud.py
@@ -10,7 +10,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for soundclound directive."""
name = "rest_soundcloud"
@@ -31,7 +30,6 @@ src="https://w.soundcloud.com/player/?url=http://api.soundcloud.com/{preslug}/""
class SoundCloud(Directive):
-
"""reST extension for inserting SoundCloud embedded music.
Usage:
@@ -70,7 +68,6 @@ class SoundCloud(Directive):
class SoundCloudPlaylist(SoundCloud):
-
"""reST directive for SoundCloud playlists."""
preslug = "playlists"
diff --git a/nikola/plugins/compile/rest/thumbnail.plugin b/nikola/plugins/compile/rest/thumbnail.plugin
index 0084310..3324c31 100644
--- a/nikola/plugins/compile/rest/thumbnail.plugin
+++ b/nikola/plugins/compile/rest/thumbnail.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Pelle Nilsson
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = reST directive to facilitate enlargeable images with thumbnails
diff --git a/nikola/plugins/compile/rest/thumbnail.py b/nikola/plugins/compile/rest/thumbnail.py
index 1fae06c..c24134a 100644
--- a/nikola/plugins/compile/rest/thumbnail.py
+++ b/nikola/plugins/compile/rest/thumbnail.py
@@ -35,7 +35,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for thumbnail directive."""
name = "rest_thumbnail"
@@ -48,7 +47,6 @@ class Plugin(RestExtension):
class Thumbnail(Figure):
-
"""Thumbnail directive for reST."""
def align(argument):
@@ -70,8 +68,12 @@ class Thumbnail(Figure):
def run(self):
"""Run the thumbnail directive."""
uri = directives.uri(self.arguments[0])
+ if uri.endswith('.svg'):
+ # the ? at the end makes docutil output an <img> instead of an object for the svg, which colorbox requires
+ self.arguments[0] = '.thumbnail'.join(os.path.splitext(uri)) + '?'
+ else:
+ self.arguments[0] = '.thumbnail'.join(os.path.splitext(uri))
self.options['target'] = uri
- self.arguments[0] = '.thumbnail'.join(os.path.splitext(uri))
if self.content:
(node,) = Figure.run(self)
else:
diff --git a/nikola/plugins/compile/rest/vimeo.py b/nikola/plugins/compile/rest/vimeo.py
index c694a87..29ce5c1 100644
--- a/nikola/plugins/compile/rest/vimeo.py
+++ b/nikola/plugins/compile/rest/vimeo.py
@@ -37,7 +37,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for vimeo reST directive."""
name = "rest_vimeo"
@@ -60,7 +59,6 @@ VIDEO_DEFAULT_WIDTH = 281
class Vimeo(Directive):
-
"""reST extension for inserting vimeo embedded videos.
Usage:
diff --git a/nikola/plugins/compile/rest/youtube.py b/nikola/plugins/compile/rest/youtube.py
index 6c5c211..b3b84b0 100644
--- a/nikola/plugins/compile/rest/youtube.py
+++ b/nikola/plugins/compile/rest/youtube.py
@@ -34,7 +34,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for the youtube directive."""
name = "rest_youtube"
@@ -54,7 +53,6 @@ src="//www.youtube.com/embed/{yid}?rel=0&amp;hd=1&amp;wmode=transparent"
class Youtube(Directive):
-
"""reST extension for inserting youtube embedded videos.
Usage:
diff --git a/nikola/plugins/misc/scan_posts.plugin b/nikola/plugins/misc/scan_posts.plugin
index 6d2351f..f4af811 100644
--- a/nikola/plugins/misc/scan_posts.plugin
+++ b/nikola/plugins/misc/scan_posts.plugin
@@ -5,6 +5,6 @@ Module = scan_posts
[Documentation]
Author = Roberto Alsina
Version = 1.0
-Website = http://getnikola.com
+Website = https://getnikola.com/
Description = Scan posts and create timeline
diff --git a/nikola/plugins/misc/scan_posts.py b/nikola/plugins/misc/scan_posts.py
index 1f4f995..9db4533 100644
--- a/nikola/plugins/misc/scan_posts.py
+++ b/nikola/plugins/misc/scan_posts.py
@@ -37,7 +37,6 @@ from nikola.post import Post
class ScanPosts(PostScanner):
-
"""Scan posts in the site."""
name = "scan_posts"
diff --git a/nikola/plugins/task/archive.plugin b/nikola/plugins/task/archive.plugin
index 25f1195..eb079da 100644
--- a/nikola/plugins/task/archive.plugin
+++ b/nikola/plugins/task/archive.plugin
@@ -5,7 +5,7 @@ module = archive
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Generates the blog's archive pages.
[Nikola]
diff --git a/nikola/plugins/task/archive.py b/nikola/plugins/task/archive.py
index 126aed4..3cdd33b 100644
--- a/nikola/plugins/task/archive.py
+++ b/nikola/plugins/task/archive.py
@@ -37,7 +37,6 @@ from nikola.utils import config_changed, adjust_name_for_index_path, adjust_name
class Archive(Task):
-
"""Render the post archives."""
name = "render_archive"
@@ -53,7 +52,7 @@ class Archive(Task):
"""Prepare an archive task."""
# name: used to build permalink and destination
# posts, items: posts or items; only one of them should be used,
- # the other be None
+ # the other should be None
# template_name: name of the template to use
# title: the (translated) title for the generated page
# deps_translatable: dependencies (None if not added)
@@ -175,10 +174,10 @@ class Archive(Task):
if not kw["create_monthly_archive"] or kw["create_full_archives"]:
yield self._generate_posts_task(kw, year, lang, posts, title, deps_translatable)
else:
- months = set([(m.split('/')[1], self.site.link("archive", m, lang)) for m in self.site.posts_per_month.keys() if m.startswith(str(year))])
+ months = set([(m.split('/')[1], self.site.link("archive", m, lang), len(self.site.posts_per_month[m])) for m in self.site.posts_per_month.keys() if m.startswith(str(year))])
months = sorted(list(months))
months.reverse()
- items = [[nikola.utils.LocaleBorg().get_month_name(int(month), lang), link] for month, link in months]
+ items = [[nikola.utils.LocaleBorg().get_month_name(int(month), lang), link, count] for month, link, count in months]
yield self._prepare_task(kw, year, lang, None, items, "list.tmpl", title, deps_translatable)
if not kw["create_monthly_archive"] and not kw["create_full_archives"] and not kw["create_daily_archive"]:
@@ -219,11 +218,16 @@ class Archive(Task):
years.sort(reverse=True)
kw['years'] = years
for lang in kw["translations"]:
- items = [(y, self.site.link("archive", y, lang)) for y in years]
+ items = [(y, self.site.link("archive", y, lang), len(self.site.posts_per_year[y])) for y in years]
yield self._prepare_task(kw, None, lang, None, items, "list.tmpl", kw["messages"][lang]["Archive"])
def archive_path(self, name, lang, is_feed=False):
- """Return archive paths."""
+ """Link to archive path, name is the year.
+
+ Example:
+
+ link://archive/2013 => /archives/2013/index.html
+ """
if is_feed:
extension = ".atom"
archive_file = os.path.splitext(self.site.config['ARCHIVE_FILENAME'])[0] + extension
@@ -241,5 +245,10 @@ class Archive(Task):
archive_file] if _f]
def archive_atom_path(self, name, lang):
- """Return Atom archive paths."""
+ """Link to atom archive path, name is the year.
+
+ Example:
+
+ link://archive_atom/2013 => /archives/2013/index.atom
+ """
return self.archive_path(name, lang, is_feed=True)
diff --git a/nikola/plugins/task/authors.plugin b/nikola/plugins/task/authors.plugin
new file mode 100644
index 0000000..3fc4ef2
--- /dev/null
+++ b/nikola/plugins/task/authors.plugin
@@ -0,0 +1,10 @@
+[Core]
+Name = render_authors
+Module = authors
+
+[Documentation]
+Author = Juanjo Conti
+Version = 0.1
+Website = http://getnikola.com
+Description = Render the author pages and feeds.
+
diff --git a/nikola/plugins/task/authors.py b/nikola/plugins/task/authors.py
new file mode 100644
index 0000000..081d21d
--- /dev/null
+++ b/nikola/plugins/task/authors.py
@@ -0,0 +1,316 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © 2015 Juanjo Conti.
+
+# 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.
+
+"""Render the author pages and feeds."""
+
+from __future__ import unicode_literals
+import os
+import natsort
+try:
+ from urlparse import urljoin
+except ImportError:
+ from urllib.parse import urljoin # NOQA
+from collections import defaultdict
+
+from nikola.plugin_categories import Task
+from nikola import utils
+
+
+class RenderAuthors(Task):
+ """Render the author pages and feeds."""
+
+ name = "render_authors"
+ posts_per_author = None
+
+ def set_site(self, site):
+ """Set Nikola site."""
+ if site.config["ENABLE_AUTHOR_PAGES"]:
+ site.register_path_handler('author_index', self.author_index_path)
+ site.register_path_handler('author', self.author_path)
+ site.register_path_handler('author_atom', self.author_atom_path)
+ site.register_path_handler('author_rss', self.author_rss_path)
+ return super(RenderAuthors, self).set_site(site)
+
+ def gen_tasks(self):
+ """Render the author pages and feeds."""
+ kw = {
+ "translations": self.site.config["TRANSLATIONS"],
+ "blog_title": self.site.config["BLOG_TITLE"],
+ "site_url": self.site.config["SITE_URL"],
+ "base_url": self.site.config["BASE_URL"],
+ "messages": self.site.MESSAGES,
+ "output_folder": self.site.config['OUTPUT_FOLDER'],
+ "filters": self.site.config['FILTERS'],
+ 'author_path': self.site.config['AUTHOR_PATH'],
+ "author_pages_are_indexes": self.site.config['AUTHOR_PAGES_ARE_INDEXES'],
+ "generate_rss": self.site.config['GENERATE_RSS'],
+ "feed_teasers": self.site.config["FEED_TEASERS"],
+ "feed_plain": self.site.config["FEED_PLAIN"],
+ "feed_link_append_query": self.site.config["FEED_LINKS_APPEND_QUERY"],
+ "show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
+ "feed_length": self.site.config['FEED_LENGTH'],
+ "tzinfo": self.site.tzinfo,
+ "pretty_urls": self.site.config['PRETTY_URLS'],
+ "strip_indexes": self.site.config['STRIP_INDEXES'],
+ "index_file": self.site.config['INDEX_FILE'],
+ }
+
+ yield self.group_task()
+ self.site.scan_posts()
+
+ generate_author_pages = self.site.config["ENABLE_AUTHOR_PAGES"] and len(self._posts_per_author()) > 1
+ self.site.GLOBAL_CONTEXT["author_pages_generated"] = generate_author_pages
+ if generate_author_pages:
+ yield self.list_authors_page(kw)
+
+ if not self._posts_per_author(): # this may be self.site.posts_per_author
+ return
+
+ author_list = list(self._posts_per_author().items())
+
+ def render_lists(author, posts):
+ """Render author pages as RSS files and lists/indexes."""
+ post_list = sorted(posts, key=lambda a: a.date)
+ post_list.reverse()
+ for lang in kw["translations"]:
+ if kw["show_untranslated_posts"]:
+ filtered_posts = post_list
+ else:
+ filtered_posts = [x for x in post_list if x.is_translation_available(lang)]
+ if kw["generate_rss"]:
+ yield self.author_rss(author, lang, filtered_posts, kw)
+ # Render HTML
+ if kw['author_pages_are_indexes']:
+ yield self.author_page_as_index(author, lang, filtered_posts, kw)
+ else:
+ yield self.author_page_as_list(author, lang, filtered_posts, kw)
+
+ for author, posts in author_list:
+ for task in render_lists(author, posts):
+ yield task
+
+ def _create_authors_page(self, kw):
+ """Create a global "all authors" page for each language."""
+ template_name = "authors.tmpl"
+ kw = kw.copy()
+ for lang in kw["translations"]:
+ authors = natsort.natsorted([author for author in self._posts_per_author().keys()],
+ alg=natsort.ns.F | natsort.ns.IC)
+ has_authors = (authors != [])
+ kw['authors'] = authors
+ output_name = os.path.join(
+ kw['output_folder'], self.site.path('author_index', None, lang))
+ context = {}
+ if has_authors:
+ context["title"] = kw["messages"][lang]["Authors"]
+ context["items"] = [(author, self.site.link("author", author, lang)) for author
+ in authors]
+ context["description"] = context["title"]
+ else:
+ context["items"] = None
+ context["permalink"] = self.site.link("author_index", None, lang)
+ context["pagekind"] = ["list", "authors_page"]
+ task = self.site.generic_post_list_renderer(
+ lang,
+ [],
+ output_name,
+ template_name,
+ kw['filters'],
+ context,
+ )
+ task['uptodate'] = task['uptodate'] + [utils.config_changed(kw, 'nikola.plugins.task.authors:page')]
+ task['basename'] = str(self.name)
+ yield task
+
+ def list_authors_page(self, kw):
+ """Create a global "all authors" page for each language."""
+ yield self._create_authors_page(kw)
+
+ def _get_title(self, author):
+ return author
+
+ def _get_description(self, author, lang):
+ descriptions = self.site.config['AUTHOR_PAGES_DESCRIPTIONS']
+ return descriptions[lang][author] if lang in descriptions and author in descriptions[lang] else None
+
+ def author_page_as_index(self, author, lang, post_list, kw):
+ """Render a sort of index page collection using only this author's posts."""
+ kind = "author"
+
+ def page_link(i, displayed_i, num_pages, force_addition, extension=None):
+ feed = "_atom" if extension == ".atom" else ""
+ return utils.adjust_name_for_index_link(self.site.link(kind + feed, author, lang), i, displayed_i, lang, self.site, force_addition, extension)
+
+ def page_path(i, displayed_i, num_pages, force_addition, extension=None):
+ feed = "_atom" if extension == ".atom" else ""
+ return utils.adjust_name_for_index_path(self.site.path(kind + feed, author, lang), i, displayed_i, lang, self.site, force_addition, extension)
+
+ context_source = {}
+ title = self._get_title(author)
+ if kw["generate_rss"]:
+ # On a author page, the feeds include the author's feeds
+ rss_link = ("""<link rel="alternate" type="application/rss+xml" """
+ """title="RSS for author """
+ """{0} ({1})" href="{2}">""".format(
+ title, lang, self.site.link(kind + "_rss", author, lang)))
+ context_source['rss_link'] = rss_link
+ context_source["author"] = title
+ indexes_title = kw["messages"][lang]["Posts by %s"] % title
+ context_source["description"] = self._get_description(author, lang)
+ context_source["pagekind"] = ["index", "author_page"]
+ template_name = "authorindex.tmpl"
+
+ yield self.site.generic_index_renderer(lang, post_list, indexes_title, template_name, context_source, kw, str(self.name), page_link, page_path)
+
+ def author_page_as_list(self, author, lang, post_list, kw):
+ """Render a single flat link list with this author's posts."""
+ kind = "author"
+ template_name = "author.tmpl"
+ output_name = os.path.join(kw['output_folder'], self.site.path(
+ kind, author, lang))
+ context = {}
+ context["lang"] = lang
+ title = self._get_title(author)
+ context["author"] = title
+ context["title"] = kw["messages"][lang]["Posts by %s"] % title
+ context["posts"] = post_list
+ context["permalink"] = self.site.link(kind, author, lang)
+ context["kind"] = kind
+ context["description"] = self._get_description(author, lang)
+ context["pagekind"] = ["list", "author_page"]
+ task = self.site.generic_post_list_renderer(
+ lang,
+ post_list,
+ output_name,
+ template_name,
+ kw['filters'],
+ context,
+ )
+ task['uptodate'] = task['uptodate'] + [utils.config_changed(kw, 'nikola.plugins.task.authors:list')]
+ task['basename'] = str(self.name)
+ yield task
+
+ def author_rss(self, author, lang, posts, kw):
+ """Create a RSS feed for a single author in a given language."""
+ kind = "author"
+ # Render RSS
+ output_name = os.path.normpath(
+ os.path.join(kw['output_folder'],
+ self.site.path(kind + "_rss", author, lang)))
+ feed_url = urljoin(self.site.config['BASE_URL'], self.site.link(kind + "_rss", author, lang).lstrip('/'))
+ deps = []
+ deps_uptodate = []
+ post_list = sorted(posts, key=lambda a: a.date)
+ post_list.reverse()
+ for post in post_list:
+ deps += post.deps(lang)
+ deps_uptodate += post.deps_uptodate(lang)
+ task = {
+ 'basename': str(self.name),
+ 'name': output_name,
+ 'file_dep': deps,
+ 'targets': [output_name],
+ 'actions': [(utils.generic_rss_renderer,
+ (lang, "{0} ({1})".format(kw["blog_title"](lang), self._get_title(author)),
+ kw["site_url"], None, post_list,
+ output_name, kw["feed_teasers"], kw["feed_plain"], kw['feed_length'],
+ feed_url, None, kw["feed_link_append_query"]))],
+ 'clean': True,
+ 'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.authors:rss')] + deps_uptodate,
+ 'task_dep': ['render_posts'],
+ }
+ return utils.apply_filters(task, kw['filters'])
+
+ def slugify_author_name(self, name):
+ """Slugify an author name."""
+ if self.site.config['SLUG_AUTHOR_PATH']:
+ name = utils.slugify(name)
+ return name
+
+ def author_index_path(self, name, lang):
+ """Link to the author's index.
+
+ Example:
+
+ link://authors/ => /authors/index.html
+ """
+ return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ self.site.config['AUTHOR_PATH'],
+ self.site.config['INDEX_FILE']] if _f]
+
+ def author_path(self, name, lang):
+ """Link to an author's page.
+
+ Example:
+
+ link://author/joe => /authors/joe.html
+ """
+ if self.site.config['PRETTY_URLS']:
+ return [_f for _f in [
+ self.site.config['TRANSLATIONS'][lang],
+ self.site.config['AUTHOR_PATH'],
+ self.slugify_author_name(name),
+ self.site.config['INDEX_FILE']] if _f]
+ else:
+ return [_f for _f in [
+ self.site.config['TRANSLATIONS'][lang],
+ self.site.config['AUTHOR_PATH'],
+ self.slugify_author_name(name) + ".html"] if _f]
+
+ def author_atom_path(self, name, lang):
+ """Link to an author's Atom feed.
+
+ Example:
+
+ link://author_atom/joe => /authors/joe.atom
+ """
+ return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ self.site.config['AUTHOR_PATH'], self.slugify_author_name(name) + ".atom"] if
+ _f]
+
+ def author_rss_path(self, name, lang):
+ """Link to an author's RSS feed.
+
+ Example:
+
+ link://author_rss/joe => /authors/joe.rss
+ """
+ return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ self.site.config['AUTHOR_PATH'], self.slugify_author_name(name) + ".xml"] if
+ _f]
+
+ def _add_extension(self, path, extension):
+ path[-1] += extension
+ return path
+
+ def _posts_per_author(self):
+ """Return a dict of posts per author."""
+ if self.posts_per_author is None:
+ self.posts_per_author = defaultdict(list)
+ for post in self.site.timeline:
+ if post.is_post:
+ self.posts_per_author[post.author()].append(post)
+ return self.posts_per_author
diff --git a/nikola/plugins/task/bundles.plugin b/nikola/plugins/task/bundles.plugin
index ca997d0..b5bf6e4 100644
--- a/nikola/plugins/task/bundles.plugin
+++ b/nikola/plugins/task/bundles.plugin
@@ -5,7 +5,7 @@ module = bundles
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Theme bundles using WebAssets
[Nikola]
diff --git a/nikola/plugins/task/bundles.py b/nikola/plugins/task/bundles.py
index b9c57b9..e709133 100644
--- a/nikola/plugins/task/bundles.py
+++ b/nikola/plugins/task/bundles.py
@@ -40,7 +40,6 @@ from nikola import utils
class BuildBundles(LateTask):
-
"""Bundle assets using WebAssets."""
name = "create_bundles"
@@ -52,6 +51,7 @@ class BuildBundles(LateTask):
utils.req_missing(['webassets'], 'USE_BUNDLES', optional=True)
self.logger.warn('Setting USE_BUNDLES to False.')
site.config['USE_BUNDLES'] = False
+ site._GLOBAL_CONTEXT['use_bundles'] = False
super(BuildBundles, self).set_site(site)
def gen_tasks(self):
@@ -100,7 +100,11 @@ class BuildBundles(LateTask):
files.append(os.path.join(dname, fname))
file_dep = [os.path.join(kw['output_folder'], fname)
for fname in files if
- utils.get_asset_path(fname, self.site.THEMES, self.site.config['FILES_FOLDERS']) or fname == os.path.join('assets', 'css', 'code.css')]
+ utils.get_asset_path(
+ fname,
+ self.site.THEMES,
+ self.site.config['FILES_FOLDERS'],
+ output_dir=kw['output_folder']) or fname == os.path.join('assets', 'css', 'code.css')]
# code.css will be generated by us if it does not exist in
# FILES_FOLDERS or theme assets. It is guaranteed that the
# generation will happen before this task.
diff --git a/nikola/plugins/task/copy_assets.plugin b/nikola/plugins/task/copy_assets.plugin
index c182150..ddd38df 100644
--- a/nikola/plugins/task/copy_assets.plugin
+++ b/nikola/plugins/task/copy_assets.plugin
@@ -5,7 +5,7 @@ module = copy_assets
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Copy theme assets into output.
[Nikola]
diff --git a/nikola/plugins/task/copy_assets.py b/nikola/plugins/task/copy_assets.py
index 58521d4..2cab71a 100644
--- a/nikola/plugins/task/copy_assets.py
+++ b/nikola/plugins/task/copy_assets.py
@@ -36,7 +36,6 @@ from nikola import utils
class CopyAssets(Task):
-
"""Copy theme assets into output."""
name = "copy_assets"
@@ -61,10 +60,7 @@ class CopyAssets(Task):
code_css_path = os.path.join(kw['output_folder'], 'assets', 'css', 'code.css')
code_css_input = utils.get_asset_path('assets/css/code.css',
themes=kw['themes'],
- files_folders=kw['files_folders'])
-
- kw["code.css_input"] = code_css_input
-
+ files_folders=kw['files_folders'], output_dir=None)
yield self.group_task()
for theme_name in kw['themes']:
@@ -77,7 +73,9 @@ class CopyAssets(Task):
task['uptodate'] = [utils.config_changed(kw, 'nikola.plugins.task.copy_assets')]
task['basename'] = self.name
if code_css_input:
- task['file_dep'] = [code_css_input]
+ if 'file_dep' not in task:
+ task['file_dep'] = []
+ task['file_dep'].append(code_css_input)
yield utils.apply_filters(task, kw['filters'])
# Check whether or not there is a code.css file around.
diff --git a/nikola/plugins/task/copy_files.plugin b/nikola/plugins/task/copy_files.plugin
index ce8f5d0..e4bb1cf 100644
--- a/nikola/plugins/task/copy_files.plugin
+++ b/nikola/plugins/task/copy_files.plugin
@@ -5,7 +5,7 @@ module = copy_files
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Copy static files into the output.
[Nikola]
diff --git a/nikola/plugins/task/copy_files.py b/nikola/plugins/task/copy_files.py
index 1232248..0488011 100644
--- a/nikola/plugins/task/copy_files.py
+++ b/nikola/plugins/task/copy_files.py
@@ -33,7 +33,6 @@ from nikola import utils
class CopyFiles(Task):
-
"""Copy static files into the output folder."""
name = "copy_files"
diff --git a/nikola/plugins/task/galleries.plugin b/nikola/plugins/task/galleries.plugin
index 9d3fa28..2064e68 100644
--- a/nikola/plugins/task/galleries.plugin
+++ b/nikola/plugins/task/galleries.plugin
@@ -5,7 +5,7 @@ module = galleries
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create image galleries automatically.
[Nikola]
diff --git a/nikola/plugins/task/galleries.py b/nikola/plugins/task/galleries.py
index c0df4a4..d3f1db7 100644
--- a/nikola/plugins/task/galleries.py
+++ b/nikola/plugins/task/galleries.py
@@ -57,7 +57,6 @@ _image_size_cache = {}
class Galleries(Task, ImageProcessor):
-
"""Render image galleries."""
name = 'render_galleries'
@@ -122,20 +121,45 @@ class Galleries(Task, ImageProcessor):
sys.exit(1)
def gallery_path(self, name, lang):
- """Return a gallery path."""
+ """Link to an image gallery's path.
+
+ It will try to find a gallery with that name if it's not ambiguous
+ or with that path. For example:
+
+ link://gallery/london => /galleries/trips/london/index.html
+
+ link://gallery/trips/london => /galleries/trips/london/index.html
+ """
gallery_path = self._find_gallery_path(name)
return [_f for _f in [self.site.config['TRANSLATIONS'][lang]] +
gallery_path.split(os.sep) +
[self.site.config['INDEX_FILE']] if _f]
def gallery_global_path(self, name, lang):
- """Return the global gallery path, which contains images."""
+ """Link to the global gallery path, which contains all the images in galleries.
+
+ There is only one copy of an image on multilingual blogs, in the site root.
+
+ link://gallery_global/london => /galleries/trips/london/index.html
+
+ link://gallery_global/trips/london => /galleries/trips/london/index.html
+
+ (a ``gallery`` link could lead to eg. /en/galleries/trips/london/index.html)
+ """
gallery_path = self._find_gallery_path(name)
return [_f for _f in gallery_path.split(os.sep) +
[self.site.config['INDEX_FILE']] if _f]
def gallery_rss_path(self, name, lang):
- """Return path to the RSS file for a gallery."""
+ """Link to an image gallery's RSS feed.
+
+ It will try to find a gallery with that name if it's not ambiguous
+ or with that path. For example:
+
+ link://gallery_rss/london => /galleries/trips/london/rss.xml
+
+ link://gallery_rss/trips/london => /galleries/trips/london/rss.xml
+ """
gallery_path = self._find_gallery_path(name)
return [_f for _f in [self.site.config['TRANSLATIONS'][lang]] +
gallery_path.split(os.sep) +
@@ -538,9 +562,12 @@ class Galleries(Task, ImageProcessor):
for img, thumb, title in zip(img_list, thumbs, img_titles):
w, h = _image_size_cache.get(thumb, (None, None))
if w is None:
- im = Image.open(thumb)
- w, h = im.size
- _image_size_cache[thumb] = w, h
+ if os.path.splitext(thumb)[1] in ['.svg', '.svgz']:
+ w, h = 200, 200
+ else:
+ im = Image.open(thumb)
+ w, h = im.size
+ _image_size_cache[thumb] = w, h
# Thumbs are files in output, we need URLs
photo_array.append({
'url': url_from_path(img),
@@ -587,7 +614,7 @@ class Galleries(Task, ImageProcessor):
description='',
lastBuildDate=datetime.datetime.utcnow(),
items=items,
- generator='http://getnikola.com/',
+ generator='https://getnikola.com/',
language=lang
)
diff --git a/nikola/plugins/task/gzip.plugin b/nikola/plugins/task/gzip.plugin
index 7834d22..d3a34ee 100644
--- a/nikola/plugins/task/gzip.plugin
+++ b/nikola/plugins/task/gzip.plugin
@@ -5,7 +5,7 @@ module = gzip
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create gzipped copies of files
[Nikola]
diff --git a/nikola/plugins/task/gzip.py b/nikola/plugins/task/gzip.py
index cf16f63..aaa213d 100644
--- a/nikola/plugins/task/gzip.py
+++ b/nikola/plugins/task/gzip.py
@@ -35,7 +35,6 @@ from nikola.plugin_categories import TaskMultiplier
class GzipFiles(TaskMultiplier):
-
"""If appropiate, create tasks to create gzipped versions of files."""
name = "gzip"
diff --git a/nikola/plugins/task/indexes.plugin b/nikola/plugins/task/indexes.plugin
index d9b0e5f..553b5ad 100644
--- a/nikola/plugins/task/indexes.plugin
+++ b/nikola/plugins/task/indexes.plugin
@@ -5,7 +5,7 @@ module = indexes
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Generates the blog's index pages.
[Nikola]
diff --git a/nikola/plugins/task/indexes.py b/nikola/plugins/task/indexes.py
index c02818e..2ab97fa 100644
--- a/nikola/plugins/task/indexes.py
+++ b/nikola/plugins/task/indexes.py
@@ -29,23 +29,45 @@
from __future__ import unicode_literals
from collections import defaultdict
import os
+try:
+ from urlparse import urljoin
+except ImportError:
+ from urllib.parse import urljoin # NOQA
from nikola.plugin_categories import Task
from nikola import utils
class Indexes(Task):
-
"""Render the blog indexes."""
name = "render_indexes"
def set_site(self, site):
"""Set Nikola site."""
+ self.number_of_pages = dict()
+ self.number_of_pages_section = {lang: dict() for lang in site.config['TRANSLATIONS']}
site.register_path_handler('index', self.index_path)
site.register_path_handler('index_atom', self.index_atom_path)
+ site.register_path_handler('section_index', self.index_section_path)
+ site.register_path_handler('section_index_atom', self.index_section_atom_path)
return super(Indexes, self).set_site(site)
+ def _get_filtered_posts(self, lang, show_untranslated_posts):
+ """Return a filtered list of all posts for the given language.
+
+ If show_untranslated_posts is True, will only include posts which
+ are translated to the given language. Otherwise, returns all posts.
+ """
+ if show_untranslated_posts:
+ return self.site.posts
+ else:
+ return [x for x in self.site.posts if x.is_translation_available(lang)]
+
+ def _compute_number_of_pages(self, filtered_posts, posts_count):
+ """Given a list of posts and the maximal number of posts per page, computes the number of pages needed."""
+ return min(1, (len(filtered_posts) + posts_count - 1) // posts_count)
+
def gen_tasks(self):
"""Render the blog indexes."""
self.site.scan_posts()
@@ -56,16 +78,16 @@ class Indexes(Task):
"messages": self.site.MESSAGES,
"output_folder": self.site.config['OUTPUT_FOLDER'],
"filters": self.site.config['FILTERS'],
+ "index_file": self.site.config['INDEX_FILE'],
"show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
"index_display_post_count": self.site.config['INDEX_DISPLAY_POST_COUNT'],
"indexes_title": self.site.config['INDEXES_TITLE'],
+ "strip_indexes": self.site.config['STRIP_INDEXES'],
"blog_title": self.site.config["BLOG_TITLE"],
"generate_atom": self.site.config["GENERATE_ATOM"],
}
template_name = "index.tmpl"
- posts = self.site.posts
- self.number_of_pages = dict()
for lang in kw["translations"]:
def page_link(i, displayed_i, num_pages, force_addition, extension=None):
feed = "_atom" if extension == ".atom" else ""
@@ -77,19 +99,75 @@ class Indexes(Task):
return utils.adjust_name_for_index_path(self.site.path("index" + feed, None, lang), i, displayed_i,
lang, self.site, force_addition, extension)
- if kw["show_untranslated_posts"]:
- filtered_posts = posts
- else:
- filtered_posts = [x for x in posts if x.is_translation_available(lang)]
+ filtered_posts = self._get_filtered_posts(lang, kw["show_untranslated_posts"])
indexes_title = kw['indexes_title'](lang) or kw['blog_title'](lang)
- self.number_of_pages[lang] = (len(filtered_posts) + kw['index_display_post_count'] - 1) // kw['index_display_post_count']
+ self.number_of_pages[lang] = self._compute_number_of_pages(filtered_posts, kw['index_display_post_count'])
context = {}
- context["pagekind"] = ["index"]
+ context["pagekind"] = ["main_index", "index"]
yield self.site.generic_index_renderer(lang, filtered_posts, indexes_title, template_name, context, kw, 'render_indexes', page_link, page_path)
+ if self.site.config['POSTS_SECTIONS']:
+
+ kw["posts_section_are_indexes"] = self.site.config['POSTS_SECTION_ARE_INDEXES']
+ index_len = len(kw['index_file'])
+
+ groups = defaultdict(list)
+ for p in filtered_posts:
+ groups[p.section_slug(lang)].append(p)
+
+ # don't build sections when there is only one, aka. default setups
+ if not len(groups.items()) > 1:
+ continue
+
+ for section_slug, post_list in groups.items():
+ self.number_of_pages_section[lang][section_slug] = self._compute_number_of_pages(post_list, kw['index_display_post_count'])
+
+ def cat_link(i, displayed_i, num_pages, force_addition, extension=None):
+ feed = "_atom" if extension == ".atom" else ""
+ return utils.adjust_name_for_index_link(self.site.link("section_index" + feed, section_slug, lang), i, displayed_i,
+ lang, self.site, force_addition, extension)
+
+ def cat_path(i, displayed_i, num_pages, force_addition, extension=None):
+ feed = "_atom" if extension == ".atom" else ""
+ return utils.adjust_name_for_index_path(self.site.path("section_index" + feed, section_slug, lang), i, displayed_i,
+ lang, self.site, force_addition, extension)
+
+ context = {}
+
+ short_destination = os.path.join(section_slug, kw['index_file'])
+ link = short_destination.replace('\\', '/')
+ if kw['strip_indexes'] and link[-(1 + index_len):] == '/' + kw['index_file']:
+ link = link[:-index_len]
+ context["permalink"] = link
+ context["pagekind"] = ["section_page"]
+ context["description"] = self.site.config['POSTS_SECTION_DESCRIPTIONS'](lang)[section_slug] if section_slug in self.site.config['POSTS_SECTION_DESCRIPTIONS'](lang) else ""
+
+ if kw["posts_section_are_indexes"]:
+ context["pagekind"].append("index")
+ kw["posts_section_title"] = self.site.config['POSTS_SECTION_TITLE'](lang)
+
+ section_title = None
+ if type(kw["posts_section_title"]) is dict:
+ if section_slug in kw["posts_section_title"]:
+ section_title = kw["posts_section_title"][section_slug]
+ elif type(kw["posts_section_title"]) is str:
+ section_title = kw["posts_section_title"]
+ if not section_title:
+ section_title = post_list[0].section_name(lang)
+ section_title = section_title.format(name=post_list[0].section_name(lang))
+
+ task = self.site.generic_index_renderer(lang, post_list, section_title, "sectionindex.tmpl", context, kw, self.name, cat_link, cat_path)
+ else:
+ context["pagekind"].append("list")
+ output_name = os.path.join(kw['output_folder'], section_slug, kw['index_file'])
+ task = self.site.generic_post_list_renderer(lang, post_list, output_name, "list.tmpl", kw['filters'], context)
+ task['uptodate'] = [utils.config_changed(kw, 'nikola.plugins.task.indexes')]
+ task['basename'] = self.name
+ yield task
+
if not self.site.config["STORY_INDEX"]:
return
kw = {
@@ -134,7 +212,8 @@ class Indexes(Task):
should_render = False
else:
context["items"].append((post.title(lang),
- post.permalink(lang)))
+ post.permalink(lang),
+ None))
if should_render:
task = self.site.generic_post_list_renderer(lang, post_list,
@@ -147,22 +226,75 @@ class Indexes(Task):
yield task
def index_path(self, name, lang, is_feed=False):
- """Return path to an index."""
+ """Link to a numbered index.
+
+ Example:
+
+ link://index/3 => /index-3.html
+ """
extension = None
if is_feed:
extension = ".atom"
index_file = os.path.splitext(self.site.config['INDEX_FILE'])[0] + extension
else:
index_file = self.site.config['INDEX_FILE']
+ if lang in self.number_of_pages:
+ number_of_pages = self.number_of_pages[lang]
+ else:
+ number_of_pages = self._compute_number_of_pages(self._get_filtered_posts(lang, self.site.config['SHOW_UNTRANSLATED_POSTS']), self.site.config['INDEX_DISPLAY_POST_COUNT'])
+ self.number_of_pages[lang] = number_of_pages
return utils.adjust_name_for_index_path_list([_f for _f in [self.site.config['TRANSLATIONS'][lang],
self.site.config['INDEX_PATH'],
index_file] if _f],
name,
- utils.get_displayed_page_number(name, self.number_of_pages[lang], self.site),
+ utils.get_displayed_page_number(name, number_of_pages, self.site),
+ lang,
+ self.site,
+ extension=extension)
+
+ def index_section_path(self, name, lang, is_feed=False):
+ """Link to the index for a section.
+
+ Example:
+
+ link://section_index/cars => /cars/index.html
+ """
+ extension = None
+
+ if is_feed:
+ extension = ".atom"
+ index_file = os.path.splitext(self.site.config['INDEX_FILE'])[0] + extension
+ else:
+ index_file = self.site.config['INDEX_FILE']
+ if name in self.number_of_pages_section[lang]:
+ number_of_pages = self.number_of_pages_section[lang][name]
+ else:
+ posts = [post for post in self._get_filtered_posts(lang, self.site.config['SHOW_UNTRANSLATED_POSTS']) if post.section_slug(lang) == name]
+ number_of_pages = self._compute_number_of_pages(posts, self.site.config['INDEX_DISPLAY_POST_COUNT'])
+ self.number_of_pages_section[lang][name] = number_of_pages
+ return utils.adjust_name_for_index_path_list([_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ name,
+ index_file] if _f],
+ None,
+ utils.get_displayed_page_number(None, number_of_pages, self.site),
lang,
self.site,
extension=extension)
def index_atom_path(self, name, lang):
- """Return path to an Atom index."""
+ """Link to a numbered Atom index.
+
+ Example:
+
+ link://index_atom/3 => /index-3.atom
+ """
return self.index_path(name, lang, is_feed=True)
+
+ def index_section_atom_path(self, name, lang):
+ """Link to the Atom index for a section.
+
+ Example:
+
+ link://section_index_atom/cars => /cars/index.atom
+ """
+ return self.index_section_path(name, lang, is_feed=True)
diff --git a/nikola/plugins/task/listings.plugin b/nikola/plugins/task/listings.plugin
index 435234b..8fc2e2d 100644
--- a/nikola/plugins/task/listings.plugin
+++ b/nikola/plugins/task/listings.plugin
@@ -5,7 +5,7 @@ module = listings
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Render code listings into output
[Nikola]
diff --git a/nikola/plugins/task/listings.py b/nikola/plugins/task/listings.py
index 5f79724..891f361 100644
--- a/nikola/plugins/task/listings.py
+++ b/nikola/plugins/task/listings.py
@@ -28,6 +28,7 @@
from __future__ import unicode_literals, print_function
+from collections import defaultdict
import sys
import os
import lxml.html
@@ -41,16 +42,13 @@ from nikola import utils
class Listings(Task):
-
"""Render code listings."""
name = "render_listings"
def register_output_name(self, input_folder, rel_name, rel_output_name):
"""Register proper and improper file mappings."""
- if rel_name not in self.improper_input_file_mapping:
- self.improper_input_file_mapping[rel_name] = []
- self.improper_input_file_mapping[rel_name].append(rel_output_name)
+ self.improper_input_file_mapping[rel_name].add(rel_output_name)
self.proper_input_file_mapping[os.path.join(input_folder, rel_name)] = rel_output_name
self.proper_input_file_mapping[rel_output_name] = rel_output_name
@@ -85,7 +83,7 @@ class Listings(Task):
# a list is needed. This is needed for compatibility to previous Nikola
# versions, where there was no need to specify the input directory name
# when asking for a link via site.link('listing', ...).
- self.improper_input_file_mapping = {}
+ self.improper_input_file_mapping = defaultdict(set)
# proper_input_file_mapping maps relative input file (relative to CWD)
# to a generated output file. Since we don't allow an input directory
@@ -255,7 +253,16 @@ class Listings(Task):
}, self.kw["filters"])
def listing_path(self, namep, lang):
- """Return path to a listing."""
+ """A link to a listing.
+
+ It will try to use the file name if it's not ambiguous, or the file path.
+
+ Example:
+
+ link://listing/hello.py => /listings/tutorial/hello.py.html
+
+ link://listing/tutorial/hello.py => /listings/tutorial/hello.py.html
+ """
namep = namep.replace('/', os.sep)
nameh = namep + '.html'
for name in (namep, nameh):
@@ -271,7 +278,7 @@ class Listings(Task):
sys.exit(1)
if len(self.site.config['LISTINGS_FOLDERS']) > 1:
utils.LOGGER.notice("Using listings names in site.link() without input directory prefix while configuration's LISTINGS_FOLDERS has more than one entry.")
- name = self.improper_input_file_mapping[name][0]
+ name = list(self.improper_input_file_mapping[name])[0]
break
else:
utils.LOGGER.error("Unknown listing name {0}!".format(namep))
diff --git a/nikola/plugins/task/pages.plugin b/nikola/plugins/task/pages.plugin
index 023d41b..1bdc7f4 100644
--- a/nikola/plugins/task/pages.plugin
+++ b/nikola/plugins/task/pages.plugin
@@ -5,7 +5,7 @@ module = pages
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create pages in the output.
[Nikola]
diff --git a/nikola/plugins/task/pages.py b/nikola/plugins/task/pages.py
index e6a8a82..8d41035 100644
--- a/nikola/plugins/task/pages.py
+++ b/nikola/plugins/task/pages.py
@@ -32,7 +32,6 @@ from nikola.utils import config_changed
class RenderPages(Task):
-
"""Render pages into output."""
name = "render_pages"
diff --git a/nikola/plugins/task/posts.plugin b/nikola/plugins/task/posts.plugin
index 79b7c51..c9578bc 100644
--- a/nikola/plugins/task/posts.plugin
+++ b/nikola/plugins/task/posts.plugin
@@ -5,7 +5,7 @@ module = posts
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create HTML fragments out of posts.
[Nikola]
diff --git a/nikola/plugins/task/posts.py b/nikola/plugins/task/posts.py
index a3a8375..8735beb 100644
--- a/nikola/plugins/task/posts.py
+++ b/nikola/plugins/task/posts.py
@@ -44,7 +44,6 @@ def update_deps(post, lang, task):
class RenderPosts(Task):
-
"""Build HTML fragments from metadata and text."""
name = "render_posts"
@@ -77,6 +76,8 @@ class RenderPosts(Task):
deps_dict = copy(kw)
deps_dict.pop('timeline')
for post in kw['timeline']:
+ if not post.is_translation_available(lang) and not self.site.config['SHOW_UNTRANSLATED_POSTS']:
+ continue
# Extra config dependencies picked from config
for p in post.fragment_deps(lang):
if p.startswith('####MAGIC####CONFIG:'):
@@ -114,7 +115,7 @@ class RenderPosts(Task):
pass
else:
flist.append(f)
- yield utils.apply_filters(task, {os.path.splitext(dest): flist})
+ yield utils.apply_filters(task, {os.path.splitext(dest)[-1]: flist})
def dependence_on_timeline(self, post, lang):
"""Check if a post depends on the timeline."""
diff --git a/nikola/plugins/task/py3_switch.plugin b/nikola/plugins/task/py3_switch.plugin
new file mode 100644
index 0000000..b0014e1
--- /dev/null
+++ b/nikola/plugins/task/py3_switch.plugin
@@ -0,0 +1,13 @@
+[Core]
+name = py3_switch
+module = py3_switch
+
+[Documentation]
+author = Roberto Alsina
+version = 1.0
+website = https://getnikola.com/
+description = Beg the user to switch to Python 3
+
+[Nikola]
+plugincategory = Task
+
diff --git a/nikola/plugins/task/py3_switch.py b/nikola/plugins/task/py3_switch.py
new file mode 100644
index 0000000..930c593
--- /dev/null
+++ b/nikola/plugins/task/py3_switch.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © 2012-2015 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.
+
+"""Beg the user to switch to python 3."""
+
+import datetime
+import os
+import random
+import sys
+
+import doit.tools
+
+from nikola.utils import get_logger, STDERR_HANDLER
+from nikola.plugin_categories import LateTask
+
+PY2_AND_NO_PY3_WARNING = """Nikola is going to deprecate Python 2 support in 2016. Your current
+version will continue to work, but please consider upgrading to Python 3.
+
+Please check http://bit.ly/1FKEsiX for details.
+"""
+PY2_WARNING = """Nikola is going to deprecate Python 2 support in 2016. You already have Python 3
+available in your system. Why not switch?
+
+Please check http://bit.ly/1FKEsiX for details.
+"""
+PY2_BARBS = [
+ "Python 2 has been deprecated for years. Stop clinging to your long gone youth and switch to Python3.",
+ "Python 2 is the safety blanket of languages. Be a big kid and switch to Python 3",
+ "Python 2 is old and busted. Python 3 is the new hotness.",
+ "Nice unicode you have there, would be a shame something happened to it.. switch to python 3!.",
+ "Don’t get in the way of progress! Upgrade to Python 3 and save a developer’s mind today!",
+ "Winners don't use Python 2 -- Signed: The FBI",
+ "Python 2? What year is it?",
+ "I just wanna tell you how I'm feeling\n"
+ "Gotta make you understand\n"
+ "Never gonna give you up [But Python 2 has to go]",
+ "The year 2009 called, and they want their Python 2.7 back.",
+]
+
+
+LOGGER = get_logger('Nikola', STDERR_HANDLER)
+
+
+def has_python_3():
+ """Check if python 3 is available."""
+ if 'win' in sys.platform:
+ py_bin = 'py.exe'
+ else:
+ py_bin = 'python3'
+ for path in os.environ["PATH"].split(os.pathsep):
+ if os.access(os.path.join(path, py_bin), os.X_OK):
+ return True
+ return False
+
+
+class Py3Switch(LateTask):
+ """Beg the user to switch to python 3."""
+
+ name = "_switch to py3"
+
+ def gen_tasks(self):
+ """Beg the user to switch to python 3."""
+ def give_warning():
+ if sys.version_info[0] == 3:
+ return
+ if has_python_3():
+ LOGGER.warn(random.choice(PY2_BARBS))
+ LOGGER.warn(PY2_WARNING)
+ else:
+ LOGGER.warn(PY2_AND_NO_PY3_WARNING)
+
+ task = {
+ 'basename': self.name,
+ 'name': 'please!',
+ 'actions': [give_warning],
+ 'clean': True,
+ 'uptodate': [doit.tools.timeout(datetime.timedelta(days=3))]
+ }
+
+ return task
diff --git a/nikola/plugins/task/redirect.plugin b/nikola/plugins/task/redirect.plugin
index c3137b9..c5a3042 100644
--- a/nikola/plugins/task/redirect.plugin
+++ b/nikola/plugins/task/redirect.plugin
@@ -5,7 +5,7 @@ module = redirect
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create redirect pages.
[Nikola]
diff --git a/nikola/plugins/task/redirect.py b/nikola/plugins/task/redirect.py
index 8530f5e..2d4eba4 100644
--- a/nikola/plugins/task/redirect.py
+++ b/nikola/plugins/task/redirect.py
@@ -35,7 +35,6 @@ from nikola import utils
class Redirect(Task):
-
"""Generate redirections."""
name = "redirect"
diff --git a/nikola/plugins/task/robots.plugin b/nikola/plugins/task/robots.plugin
index 72ce31f..7ae56c6 100644
--- a/nikola/plugins/task/robots.plugin
+++ b/nikola/plugins/task/robots.plugin
@@ -5,7 +5,7 @@ module = robots
[Documentation]
author = Daniel Aleksandersen
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Generate /robots.txt exclusion file and promote sitemap.
[Nikola]
diff --git a/nikola/plugins/task/robots.py b/nikola/plugins/task/robots.py
index 65254b6..7c7f5df 100644
--- a/nikola/plugins/task/robots.py
+++ b/nikola/plugins/task/robots.py
@@ -39,7 +39,6 @@ from nikola import utils
class RobotsFile(LateTask):
-
"""Generate a robots.txt file."""
name = "robots_file"
@@ -64,14 +63,15 @@ class RobotsFile(LateTask):
with io.open(robots_path, 'w+', encoding='utf8') as outf:
outf.write("Sitemap: {0}\n\n".format(sitemapindex_url))
+ outf.write("User-Agent: *\n")
if kw["robots_exclusions"]:
- outf.write("User-Agent: *\n")
for loc in kw["robots_exclusions"]:
outf.write("Disallow: {0}\n".format(loc))
+ outf.write("Host: {0}\n".format(urlparse(kw["base_url"]).netloc))
yield self.group_task()
- if not utils.get_asset_path("robots.txt", [], files_folders=kw["files_folders"]):
+ if not utils.get_asset_path("robots.txt", [], files_folders=kw["files_folders"], output_dir=False):
yield utils.apply_filters({
"basename": self.name,
"name": robots_path,
@@ -82,6 +82,6 @@ class RobotsFile(LateTask):
"task_dep": ["sitemap"]
}, kw["filters"])
elif kw["robots_exclusions"]:
- utils.LOGGER.warn('Did not generate robots.txt as one already exists in FILES_FOLDERS. ROBOTS_EXCLUSIONS will not have any affect on the copied fie.')
+ utils.LOGGER.warn('Did not generate robots.txt as one already exists in FILES_FOLDERS. ROBOTS_EXCLUSIONS will not have any affect on the copied file.')
else:
utils.LOGGER.debug('Did not generate robots.txt as one already exists in FILES_FOLDERS.')
diff --git a/nikola/plugins/task/rss.plugin b/nikola/plugins/task/rss.plugin
index cf9b7a7..4dd8aba 100644
--- a/nikola/plugins/task/rss.plugin
+++ b/nikola/plugins/task/rss.plugin
@@ -5,7 +5,7 @@ module = rss
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Generate RSS feeds.
[Nikola]
diff --git a/nikola/plugins/task/rss.py b/nikola/plugins/task/rss.py
index 9020a06..be57f5c 100644
--- a/nikola/plugins/task/rss.py
+++ b/nikola/plugins/task/rss.py
@@ -38,7 +38,6 @@ from nikola.plugin_categories import Task
class GenerateRSS(Task):
-
"""Generate RSS feeds."""
name = "generate_rss"
@@ -58,13 +57,14 @@ class GenerateRSS(Task):
"base_url": self.site.config["BASE_URL"],
"blog_description": self.site.config["BLOG_DESCRIPTION"],
"output_folder": self.site.config["OUTPUT_FOLDER"],
- "rss_teasers": self.site.config["RSS_TEASERS"],
- "rss_plain": self.site.config["RSS_PLAIN"],
+ "feed_teasers": self.site.config["FEED_TEASERS"],
+ "feed_plain": self.site.config["FEED_PLAIN"],
"show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
"feed_length": self.site.config['FEED_LENGTH'],
+ "feed_previewimage": self.site.config["FEED_PREVIEWIMAGE"],
"tzinfo": self.site.tzinfo,
- "rss_read_more_link": self.site.config["RSS_READ_MORE_LINK"],
- "rss_links_append_query": self.site.config["RSS_LINKS_APPEND_QUERY"],
+ "feed_read_more_link": self.site.config["FEED_READ_MORE_LINK"],
+ "feed_links_append_query": self.site.config["FEED_LINKS_APPEND_QUERY"],
}
self.site.scan_posts()
# Check for any changes in the state of use_in_feeds for any post.
@@ -96,8 +96,8 @@ class GenerateRSS(Task):
'actions': [(utils.generic_rss_renderer,
(lang, kw["blog_title"](lang), kw["site_url"],
kw["blog_description"](lang), posts, output_name,
- kw["rss_teasers"], kw["rss_plain"], kw['feed_length'], feed_url,
- None, kw["rss_links_append_query"]))],
+ kw["feed_teasers"], kw["feed_plain"], kw['feed_length'], feed_url,
+ None, kw["feed_links_append_query"]))],
'task_dep': ['render_posts'],
'clean': True,
@@ -106,6 +106,11 @@ class GenerateRSS(Task):
yield utils.apply_filters(task, kw['filters'])
def rss_path(self, name, lang):
- """Return RSS path."""
+ """A link to the RSS feed path.
+
+ Example:
+
+ link://rss => /blog/rss.xml
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
self.site.config['RSS_PATH'], 'rss.xml'] if _f]
diff --git a/nikola/plugins/task/scale_images.plugin b/nikola/plugins/task/scale_images.plugin
index d906b8c..3edd0c6 100644
--- a/nikola/plugins/task/scale_images.plugin
+++ b/nikola/plugins/task/scale_images.plugin
@@ -5,7 +5,7 @@ module = scale_images
[Documentation]
author = Pelle Nilsson
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create down-scaled images and thumbnails.
[Nikola]
diff --git a/nikola/plugins/task/scale_images.py b/nikola/plugins/task/scale_images.py
index 22ed2ab..e55dc6c 100644
--- a/nikola/plugins/task/scale_images.py
+++ b/nikola/plugins/task/scale_images.py
@@ -34,7 +34,6 @@ from nikola import utils
class ScaleImage(Task, ImageProcessor):
-
"""Resize images and create thumbnails for them."""
name = "scale_images"
diff --git a/nikola/plugins/task/sitemap.plugin b/nikola/plugins/task/sitemap.plugin
index e3c991f..83e72c4 100644
--- a/nikola/plugins/task/sitemap.plugin
+++ b/nikola/plugins/task/sitemap.plugin
@@ -5,7 +5,7 @@ module = sitemap
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Generate google sitemap.
[Nikola]
diff --git a/nikola/plugins/task/sitemap/__init__.py b/nikola/plugins/task/sitemap/__init__.py
index fd781d6..90acdd3 100644
--- a/nikola/plugins/task/sitemap/__init__.py
+++ b/nikola/plugins/task/sitemap/__init__.py
@@ -31,6 +31,7 @@ import io
import datetime
import dateutil.tz
import os
+import sys
try:
from urlparse import urljoin, urlparse
import robotparser as robotparser
@@ -39,7 +40,7 @@ except ImportError:
import urllib.robotparser as robotparser # NOQA
from nikola.plugin_categories import LateTask
-from nikola.utils import config_changed, apply_filters
+from nikola.utils import apply_filters, config_changed, encodelink
urlset_header = """<?xml version="1.0" encoding="UTF-8"?>
@@ -106,7 +107,6 @@ def get_base_path(base):
class Sitemap(LateTask):
-
"""Generate a sitemap."""
name = "sitemap"
@@ -146,7 +146,10 @@ class Sitemap(LateTask):
continue # Totally empty, not on sitemap
path = os.path.relpath(root, output)
# ignore the current directory.
- path = (path.replace(os.sep, '/') + '/').replace('./', '')
+ if path == '.':
+ path = ''
+ else:
+ path = path.replace(os.sep, '/') + '/'
lastmod = self.get_lastmod(root)
loc = urljoin(base_url, base_path + path)
if kw['index_file'] in files and kw['strip_indexes']: # ignore folders when not stripping urls
@@ -157,10 +160,10 @@ class Sitemap(LateTask):
if post:
for lang in kw['translations']:
alt_url = post.permalink(lang=lang, absolute=True)
- if loc == alt_url:
+ if encodelink(loc) == alt_url:
continue
alternates.append(alternates_format.format(lang, alt_url))
- urlset[loc] = loc_format.format(loc, lastmod, ''.join(alternates))
+ urlset[loc] = loc_format.format(encodelink(loc), lastmod, ''.join(alternates))
for fname in files:
if kw['strip_indexes'] and fname == kw['index_file']:
continue # We already mapped the folder
@@ -200,7 +203,7 @@ class Sitemap(LateTask):
path = path.replace(os.sep, '/')
lastmod = self.get_lastmod(real_path)
loc = urljoin(base_url, base_path + path)
- sitemapindex[loc] = sitemap_format.format(loc, lastmod)
+ sitemapindex[loc] = sitemap_format.format(encodelink(loc), lastmod)
continue
else:
continue # ignores all XML files except those presumed to be RSS
@@ -214,18 +217,22 @@ class Sitemap(LateTask):
if post:
for lang in kw['translations']:
alt_url = post.permalink(lang=lang, absolute=True)
- if loc == alt_url:
+ if encodelink(loc) == alt_url:
continue
alternates.append(alternates_format.format(lang, alt_url))
- urlset[loc] = loc_format.format(loc, lastmod, '\n'.join(alternates))
+ urlset[loc] = loc_format.format(encodelink(loc), lastmod, '\n'.join(alternates))
def robot_fetch(path):
"""Check if robots can fetch a file."""
for rule in kw["robots_exclusions"]:
robot = robotparser.RobotFileParser()
robot.parse(["User-Agent: *", "Disallow: {0}".format(rule)])
- if not robot.can_fetch("*", '/' + path):
- return False # not robot food
+ if sys.version_info[0] == 3:
+ if not robot.can_fetch("*", '/' + path):
+ return False # not robot food
+ else:
+ if not robot.can_fetch("*", ('/' + path).encode('utf-8')):
+ return False # not robot food
return True
def write_sitemap():
diff --git a/nikola/plugins/task/sources.plugin b/nikola/plugins/task/sources.plugin
index d232c2b..66856f1 100644
--- a/nikola/plugins/task/sources.plugin
+++ b/nikola/plugins/task/sources.plugin
@@ -5,7 +5,7 @@ module = sources
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Copy page sources into the output.
[Nikola]
diff --git a/nikola/plugins/task/sources.py b/nikola/plugins/task/sources.py
index 87b4ae7..f782ad4 100644
--- a/nikola/plugins/task/sources.py
+++ b/nikola/plugins/task/sources.py
@@ -33,7 +33,6 @@ from nikola import utils
class Sources(Task):
-
"""Copy page sources into the output."""
name = "render_sources"
diff --git a/nikola/plugins/task/tags.plugin b/nikola/plugins/task/tags.plugin
index 283a16a..c3a5be3 100644
--- a/nikola/plugins/task/tags.plugin
+++ b/nikola/plugins/task/tags.plugin
@@ -5,7 +5,7 @@ module = tags
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Render the tag pages and feeds.
[Nikola]
diff --git a/nikola/plugins/task/tags.py b/nikola/plugins/task/tags.py
index 3186636..6d9d495 100644
--- a/nikola/plugins/task/tags.py
+++ b/nikola/plugins/task/tags.py
@@ -41,7 +41,6 @@ from nikola import utils
class RenderTags(Task):
-
"""Render the tag/category pages and feeds."""
name = "render_tags"
@@ -74,9 +73,9 @@ class RenderTags(Task):
'category_prefix': self.site.config['CATEGORY_PREFIX'],
"category_pages_are_indexes": self.site.config['CATEGORY_PAGES_ARE_INDEXES'],
"generate_rss": self.site.config['GENERATE_RSS'],
- "rss_teasers": self.site.config["RSS_TEASERS"],
- "rss_plain": self.site.config["RSS_PLAIN"],
- "rss_link_append_query": self.site.config["RSS_LINKS_APPEND_QUERY"],
+ "feed_teasers": self.site.config["FEED_TEASERS"],
+ "feed_plain": self.site.config["FEED_PLAIN"],
+ "feed_link_append_query": self.site.config["FEED_LINKS_APPEND_QUERY"],
"show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
"feed_length": self.site.config['FEED_LENGTH'],
"taglist_minimum_post_count": self.site.config['TAGLIST_MINIMUM_POSTS'],
@@ -84,6 +83,10 @@ class RenderTags(Task):
"pretty_urls": self.site.config['PRETTY_URLS'],
"strip_indexes": self.site.config['STRIP_INDEXES'],
"index_file": self.site.config['INDEX_FILE'],
+ "category_pages_descriptions": self.site.config['CATEGORY_PAGES_DESCRIPTIONS'],
+ "category_pages_titles": self.site.config['CATEGORY_PAGES_TITLES'],
+ "tag_pages_descriptions": self.site.config['TAG_PAGES_DESCRIPTIONS'],
+ "tag_pages_titles": self.site.config['TAG_PAGES_TITLES'],
}
self.site.scan_posts()
@@ -168,7 +171,7 @@ class RenderTags(Task):
"""Write tag data into JSON file, for use in tag clouds."""
utils.makedirs(os.path.dirname(output_name))
with open(output_name, 'w+') as fd:
- json.dump(data, fd)
+ json.dump(data, fd, sort_keys=True)
if self.site.config['WRITE_TAG_CLOUD']:
task = {
@@ -199,7 +202,6 @@ class RenderTags(Task):
kw['tags'] = tags
output_name = os.path.join(
kw['output_folder'], self.site.path('tag_index' if has_tags else 'category_index', None, lang))
- output_name = output_name
context = {}
if has_categories and has_tags:
context["title"] = kw["messages"][lang]["Tags and Categories"]
@@ -251,6 +253,10 @@ class RenderTags(Task):
else:
return tag
+ def _get_indexes_title(self, tag, is_category, lang, messages):
+ titles = self.site.config['CATEGORY_PAGES_TITLES'] if is_category else self.site.config['TAG_PAGES_TITLES']
+ return titles[lang][tag] if lang in titles and tag in titles[lang] else messages[lang]["Posts about %s"] % tag
+
def _get_description(self, tag, is_category, lang):
descriptions = self.site.config['CATEGORY_PAGES_DESCRIPTIONS'] if is_category else self.site.config['TAG_PAGES_DESCRIPTIONS']
return descriptions[lang][tag] if lang in descriptions and tag in descriptions[lang] else None
@@ -276,7 +282,7 @@ class RenderTags(Task):
if kw["generate_rss"]:
# 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 """
+ """title="RSS for tag """
"""{0} ({1})" href="{2}">""".format(
title, lang, self.site.link(kind + "_rss", tag, lang)))
context_source['rss_link'] = rss_link
@@ -284,7 +290,7 @@ class RenderTags(Task):
context_source["category"] = tag
context_source["category_path"] = self.site.parse_category_name(tag)
context_source["tag"] = title
- indexes_title = kw["messages"][lang]["Posts about %s"] % title
+ indexes_title = self._get_indexes_title(title, is_category, lang, kw["messages"])
context_source["description"] = self._get_description(tag, is_category, lang)
if is_category:
context_source["subcategories"] = self._get_subcategories(tag)
@@ -306,7 +312,7 @@ class RenderTags(Task):
context["category"] = tag
context["category_path"] = self.site.parse_category_name(tag)
context["tag"] = title
- context["title"] = kw["messages"][lang]["Posts about %s"] % title
+ context["title"] = self._get_indexes_title(title, is_category, lang, kw["messages"])
context["posts"] = post_list
context["permalink"] = self.site.link(kind, tag, lang)
context["kind"] = kind
@@ -326,6 +332,29 @@ class RenderTags(Task):
task['basename'] = str(self.name)
yield task
+ if self.site.config['GENERATE_ATOM']:
+ yield self.atom_feed_list(kind, tag, lang, post_list, context, kw)
+
+ def atom_feed_list(self, kind, tag, lang, post_list, context, kw):
+ """Generate atom feeds for tag lists."""
+ if kind == 'tag':
+ context['feedlink'] = self.site.abs_link(self.site.path('tag_atom', tag, lang))
+ feed_path = os.path.join(kw['output_folder'], self.site.path('tag_atom', tag, lang))
+ elif kind == 'category':
+ context['feedlink'] = self.site.abs_link(self.site.path('category_atom', tag, lang))
+ feed_path = os.path.join(kw['output_folder'], self.site.path('category_atom', tag, lang))
+
+ task = {
+ 'basename': str(self.name),
+ 'name': feed_path,
+ 'targets': [feed_path],
+ 'actions': [(self.site.atom_feed_renderer, (lang, post_list, feed_path, kw['filters'], context))],
+ 'clean': True,
+ 'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.tags:atom')],
+ 'task_dep': ['render_posts'],
+ }
+ return task
+
def tag_rss(self, tag, lang, posts, kw, is_category):
"""Create a RSS feed for a single tag in a given language."""
kind = "category" if is_category else "tag"
@@ -349,8 +378,8 @@ class RenderTags(Task):
'actions': [(utils.generic_rss_renderer,
(lang, "{0} ({1})".format(kw["blog_title"](lang), self._get_title(tag, is_category)),
kw["site_url"], None, post_list,
- output_name, kw["rss_teasers"], kw["rss_plain"], kw['feed_length'],
- feed_url, None, kw["rss_link_append_query"]))],
+ output_name, kw["feed_teasers"], kw["feed_plain"], kw['feed_length'],
+ feed_url, None, kw["feed_link_append_query"]))],
'clean': True,
'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.tags:rss')] + deps_uptodate,
'task_dep': ['render_posts'],
@@ -364,41 +393,71 @@ class RenderTags(Task):
return name
def tag_index_path(self, name, lang):
- """Return path to the tag index."""
- return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['TAG_PATH'],
- self.site.config['INDEX_FILE']] if _f]
+ """A link to the tag index.
+
+ Example:
+
+ link://tag_index => /tags/index.html
+ """
+ if self.site.config['TAGS_INDEX_PATH'][lang]:
+ paths = [_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ self.site.config['TAGS_INDEX_PATH'][lang]] if _f]
+ else:
+ paths = [_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ self.site.config['TAG_PATH'][lang],
+ self.site.config['INDEX_FILE']] if _f]
+ return paths
def category_index_path(self, name, lang):
- """Return path to the category index."""
+ """A link to the category index.
+
+ Example:
+
+ link://category_index => /categories/index.html
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['CATEGORY_PATH'],
+ self.site.config['CATEGORY_PATH'][lang],
self.site.config['INDEX_FILE']] if _f]
def tag_path(self, name, lang):
- """Return path to a tag."""
+ """A link to a tag's page.
+
+ Example:
+
+ link://tag/cats => /tags/cats.html
+ """
if self.site.config['PRETTY_URLS']:
return [_f for _f in [
self.site.config['TRANSLATIONS'][lang],
- self.site.config['TAG_PATH'],
+ self.site.config['TAG_PATH'][lang],
self.slugify_tag_name(name),
self.site.config['INDEX_FILE']] if _f]
else:
return [_f for _f in [
self.site.config['TRANSLATIONS'][lang],
- self.site.config['TAG_PATH'],
+ self.site.config['TAG_PATH'][lang],
self.slugify_tag_name(name) + ".html"] if _f]
def tag_atom_path(self, name, lang):
- """Return path to a tag Atom feed."""
+ """A link to a tag's Atom feed.
+
+ Example:
+
+ link://tag_atom/cats => /tags/cats.atom
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['TAG_PATH'], self.slugify_tag_name(name) + ".atom"] if
+ self.site.config['TAG_PATH'][lang], self.slugify_tag_name(name) + ".atom"] if
_f]
def tag_rss_path(self, name, lang):
- """Return path to a tag RSS feed."""
+ """A link to a tag's RSS feed.
+
+ Example:
+
+ link://tag_rss/cats => /tags/cats.xml
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['TAG_PATH'], self.slugify_tag_name(name) + ".xml"] if
+ self.site.config['TAG_PATH'][lang], self.slugify_tag_name(name) + ".xml"] if
_f]
def slugify_category_name(self, name):
@@ -417,24 +476,39 @@ class RenderTags(Task):
return path
def category_path(self, name, lang):
- """Return path to a category."""
+ """A link to a category.
+
+ Example:
+
+ link://category/dogs => /categories/dogs.html
+ """
if self.site.config['PRETTY_URLS']:
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['CATEGORY_PATH']] if
+ self.site.config['CATEGORY_PATH'][lang]] if
_f] + self.slugify_category_name(name) + [self.site.config['INDEX_FILE']]
else:
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['CATEGORY_PATH']] if
+ self.site.config['CATEGORY_PATH'][lang]] if
_f] + self._add_extension(self.slugify_category_name(name), ".html")
def category_atom_path(self, name, lang):
- """Return path to a category Atom feed."""
+ """A link to a category's Atom feed.
+
+ Example:
+
+ link://category_atom/dogs => /categories/dogs.atom
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['CATEGORY_PATH']] if
+ self.site.config['CATEGORY_PATH'][lang]] if
_f] + self._add_extension(self.slugify_category_name(name), ".atom")
def category_rss_path(self, name, lang):
- """Return path to a category RSS feed."""
+ """A link to a category's RSS feed.
+
+ Example:
+
+ link://category_rss/dogs => /categories/dogs.xml
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['CATEGORY_PATH']] if
+ self.site.config['CATEGORY_PATH'][lang]] if
_f] + self._add_extension(self.slugify_category_name(name), ".xml")
diff --git a/nikola/plugins/template/jinja.plugin b/nikola/plugins/template/jinja.plugin
index cfe9fa8..78fd41b 100644
--- a/nikola/plugins/template/jinja.plugin
+++ b/nikola/plugins/template/jinja.plugin
@@ -5,7 +5,7 @@ module = jinja
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Support for Jinja2 templates.
[Nikola]
diff --git a/nikola/plugins/template/jinja.py b/nikola/plugins/template/jinja.py
index b02d75c..e7df102 100644
--- a/nikola/plugins/template/jinja.py
+++ b/nikola/plugins/template/jinja.py
@@ -42,7 +42,6 @@ from nikola.utils import makedirs, req_missing
class JinjaTemplates(TemplateSystem):
-
"""Support for Jinja2 templates."""
name = "jinja"
diff --git a/nikola/plugins/template/mako.plugin b/nikola/plugins/template/mako.plugin
index d256faf..308d291 100644
--- a/nikola/plugins/template/mako.plugin
+++ b/nikola/plugins/template/mako.plugin
@@ -5,7 +5,7 @@ module = mako
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Support for Mako templates.
[Nikola]
diff --git a/nikola/plugins/template/mako.py b/nikola/plugins/template/mako.py
index aed6596..6da21db 100644
--- a/nikola/plugins/template/mako.py
+++ b/nikola/plugins/template/mako.py
@@ -44,7 +44,6 @@ LOGGER = get_logger('mako', STDERR_HANDLER)
class MakoTemplates(TemplateSystem):
-
"""Support for Mako templates."""
name = "mako"