Skip to content

Commit

Permalink
merged master
Browse files Browse the repository at this point in the history
  • Loading branch information
ralsina committed Sep 7, 2015
2 parents ad24c22 + 621f2ee commit dd49ef6
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 49 deletions.
9 changes: 7 additions & 2 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ Features
--------

* Allow inheriting templates with theme name (Issue #1814)
* Made TAG_PATH translatable (Issue #1914)
* Made CATEGORY_PATH translatable (Issue #1914)
* Display post counts for archive links (Issue #2011)
* Document link/path handlers (Issue #2008)
* Made DATE_FORMAT and JS_DATE_FORMAT translatable (Issue #2032)

Bugfixes
--------

* Multi-lingual and multi-level directories confused section slug
detection (Issue #2023)
* Use Unicode strings for WordPress comment headers (Issue #2019)
* Don't add stories to author pages (Issue #2007)

Expand Down Expand Up @@ -48,8 +53,8 @@ Bugfixes
* Make nikola tabcompletion work outside sites (Issue #1983)
* Fix display of categories list in bootstrap theme (Issue #2002)
* If webassets is not installed, use unbundled assets (Issue #1992)
* Check links in Atom and sitemap files (Issue #1993)
* Link checker should check all absolute URLs to self (Issue #1991)
* Check links in Atom and sitemap files (Issue #1993)
* Link checker should check all absolute URLs to self (Issue #1991)
* Check ``img|source[@srcset]`` as part of ``check -l`` (Issue #1989)
* Clean up translations for third party components
* ``pagekind["main_index"]`` set on the main indexes to differentiate
Expand Down
6 changes: 4 additions & 2 deletions nikola/conf.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,11 @@ TIMEZONE = ${TIMEZONE}
# Note that this does not affect DATE_FORMAT.
# FORCE_ISO8601 = False

# Date format used to display post dates.
# Date format used to display post dates. (translatable)
# (str used by datetime.datetime.strftime)
# DATE_FORMAT = '%Y-%m-%d %H:%M'

# Date format used to display post dates, if local dates are used.
# Date format used to display post dates, if local dates are used. (translatable)
# (str used by moment.js)
# JS_DATE_FORMAT = 'YYYY-MM-DD HH:mm'

Expand Down Expand Up @@ -271,6 +271,7 @@ POSTS_SECTIONS = True
# output / TRANSLATION[lang] / TAG_PATH / index.html (list of tags)
# output / TRANSLATION[lang] / TAG_PATH / tag.html (list of posts for a tag)
# output / TRANSLATION[lang] / TAG_PATH / tag.xml (RSS feed for a tag)
# (translatable)
# TAG_PATH = "categories"

# If TAG_PAGES_ARE_INDEXES is set to True, each tag's page will contain
Expand Down Expand Up @@ -310,6 +311,7 @@ HIDDEN_TAGS = ['mathjax']
# output / TRANSLATION[lang] / CATEGORY_PATH / index.html (list of categories)
# output / TRANSLATION[lang] / CATEGORY_PATH / CATEGORY_PREFIX category.html (list of posts for a category)
# output / TRANSLATION[lang] / CATEGORY_PATH / CATEGORY_PREFIX category.xml (RSS feed for a category)
# (translatable)
# CATEGORY_PATH = "categories"
# CATEGORY_PREFIX = "cat_"

Expand Down
26 changes: 21 additions & 5 deletions nikola/nikola.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,13 @@ def __init__(self, **config):
'POSTS_SECTION_NAME',
'POSTS_SECTION_TITLE',
'INDEXES_PAGES',
'INDEXES_PRETTY_PAGE_URL',)
'INDEXES_PRETTY_PAGE_URL',
# PATH options (Issue #1914)
'TAG_PATH',
'CATEGORY_PATH',
'DATE_FORMAT',
'JS_DATE_FORMAT',
)

self._GLOBAL_CONTEXT_TRANSLATABLE = ('blog_author',
'blog_title',
Expand All @@ -560,10 +566,20 @@ def __init__(self, **config):
'social_buttons_code',
'search_form',
'body_end',
'extra_head_data',)
'extra_head_data',
'date_format',
'js_date_format',)
# WARNING: navigation_links SHOULD NOT be added to the list above.
# Themes ask for [lang] there and we should provide it.

# We first have to massage JS_DATE_FORMAT, otherwise we run into trouble
if 'JS_DATE_FORMAT' in self.config:
if isinstance(self.config['JS_DATE_FORMAT'], dict):
for k in self.config['JS_DATE_FORMAT']:
self.config['JS_DATE_FORMAT'][k] = json.dumps(self.config['JS_DATE_FORMAT'][k])
else:
self.config['JS_DATE_FORMAT'] = json.dumps(self.config['JS_DATE_FORMAT'])

for i in self.TRANSLATABLE_SETTINGS:
try:
self.config[i] = utils.TranslatableSetting(i, self.config[i], self.config['TRANSLATIONS'])
Expand Down Expand Up @@ -670,7 +686,7 @@ def __init__(self, **config):
if not self.config.get('COPY_SOURCES'):
self.config['SHOW_SOURCELINK'] = False

if self.config['CATEGORY_PATH'] is None:
if self.config['CATEGORY_PATH']._inp is None:
self.config['CATEGORY_PATH'] = self.config['TAG_PATH']
if self.config['CATEGORY_PAGES_ARE_INDEXES'] is None:
self.config['CATEGORY_PAGES_ARE_INDEXES'] = self.config['TAG_PAGES_ARE_INDEXES']
Expand Down Expand Up @@ -920,7 +936,7 @@ def _set_global_context(self):
'SHOW_SOURCELINK')
self._GLOBAL_CONTEXT['extra_head_data'] = self.config.get('EXTRA_HEAD_DATA')
self._GLOBAL_CONTEXT['date_fanciness'] = self.config.get('DATE_FANCINESS')
self._GLOBAL_CONTEXT['js_date_format'] = json.dumps(self.config.get('JS_DATE_FORMAT'))
self._GLOBAL_CONTEXT['js_date_format'] = self.config.get('JS_DATE_FORMAT')
self._GLOBAL_CONTEXT['colorbox_locales'] = LEGAL_VALUES['COLORBOX_LOCALES']
self._GLOBAL_CONTEXT['momentjs_locales'] = LEGAL_VALUES['MOMENTJS_LOCALES']
self._GLOBAL_CONTEXT['hidden_tags'] = self.config.get('HIDDEN_TAGS')
Expand Down Expand Up @@ -1820,7 +1836,7 @@ def atom_link(link_rel, link_type, link_href):
feed_id = lxml.etree.SubElement(feed_root, "id")
feed_id.text = self.abs_link(context["feedlink"])
feed_updated = lxml.etree.SubElement(feed_root, "updated")
feed_updated.text = post.formatted_date('webiso', datetime.datetime.now(tz=dateutil.tz.tzutc()))
feed_updated.text = utils.formatted_date('webiso', datetime.datetime.now(tz=dateutil.tz.tzutc()))
feed_author = lxml.etree.SubElement(feed_root, "author")
feed_author_name = lxml.etree.SubElement(feed_author, "name")
feed_author_name.text = self.config["BLOG_AUTHOR"](lang)
Expand Down
39 changes: 27 additions & 12 deletions nikola/plugins/command/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@
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", '')):
Expand All @@ -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)
Expand Down Expand Up @@ -162,30 +168,33 @@ def _execute(self, options, args):
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'])
url_type = self.site.config['URL_TYPE']

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
Expand Down Expand Up @@ -250,16 +259,22 @@ def analyze(self, fname, find_sources=False, check_remote=False):
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 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]:
elif self.checked_remote_targets[target] in [302, 307]:
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] > 399:
self.logger.error("Broken link in {0}: {1} [Error {2}]".format(filename, target, self.checked_remote_targets[target]))
Expand Down Expand Up @@ -352,7 +367,7 @@ def scan_links(self, find_sources=False, check_remote=False):
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)[0]:
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):
Expand All @@ -372,7 +387,7 @@ def scan_files(self):
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)]
Expand All @@ -395,7 +410,7 @@ def scan_files(self):

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)
Expand Down
2 changes: 2 additions & 0 deletions nikola/plugins/task/posts.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ def tl_ch():
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:'):
Expand Down
20 changes: 10 additions & 10 deletions nikola/plugins/task/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ def tag_index_path(self, name, lang):
link://tag_index => /tags/index.html
"""
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
self.site.config['TAG_PATH'],
self.site.config['TAG_PATH'][lang],
self.site.config['INDEX_FILE']] if _f]

def category_index_path(self, name, lang):
Expand All @@ -412,7 +412,7 @@ def category_index_path(self, name, lang):
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):
Expand All @@ -425,13 +425,13 @@ def tag_path(self, name, lang):
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):
Expand All @@ -442,7 +442,7 @@ def tag_atom_path(self, name, lang):
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):
Expand All @@ -453,7 +453,7 @@ def tag_rss_path(self, name, lang):
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):
Expand All @@ -480,11 +480,11 @@ def category_path(self, name, lang):
"""
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):
Expand All @@ -495,7 +495,7 @@ def category_atom_path(self, name, lang):
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):
Expand All @@ -506,5 +506,5 @@ def category_rss_path(self, name, lang):
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")
25 changes: 8 additions & 17 deletions nikola/post.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
# for tearDown with _reload we cannot use 'from import' to get forLocaleBorg
import nikola.utils
from .utils import (
bytes_str,
current_time,
Functionary,
LOGGER,
Expand Down Expand Up @@ -324,19 +323,7 @@ def template_name(self):

def formatted_date(self, date_format, date=None):
"""Return the formatted date as unicode."""
date = date if date else self.date

if date_format == 'webiso':
# Formatted after RFC 3339 (web ISO 8501 profile) with Zulu
# zone desgignator for times in UTC and no microsecond precision.
fmt_date = date.replace(microsecond=0).isoformat().replace('+00:00', 'Z')
else:
fmt_date = date.strftime(date_format)

# Issue #383, this changes from py2 to py3
if isinstance(fmt_date, bytes_str):
fmt_date = fmt_date.decode('utf8')
return fmt_date
return utils.formatted_date(date_format, date if date else self.date)

def formatted_updated(self, date_format):
"""Return the updated date as unicode."""
Expand Down Expand Up @@ -781,12 +768,16 @@ def section_slug(self, lang=None):
if dest[-(1 + len(self.index_file)):] == '/' + self.index_file:
dest = dest[:-(1 + len(self.index_file))]
dirname = os.path.dirname(dest)
slug = dirname
if not dirname or dirname == '.':
slug = dest.split(os.sep)
if not slug or dirname == '.':
slug = self.messages[lang]["Uncategorized"]
elif lang == slug[0]:
slug = slug[1]
else:
slug = slug[0]
else:
slug = self.meta[lang]['section'].split(',')[0] if 'section' in self.meta[lang] else self.messages[lang]["Uncategorized"]
return slug.replace(' ', '-').lower()
return utils.slugify(slug)

def permalink(self, lang=None, absolute=False, extension='.html', query=None):
"""Return permalink for a post."""
Expand Down
Loading

0 comments on commit dd49ef6

Please sign in to comment.