Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
First version of plugin.
  • Loading branch information
felixfontein committed May 2, 2018
1 parent 94555d5 commit c94cff1
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 20 deletions.
13 changes: 6 additions & 7 deletions v8/upgrade_metadata_v8/README.md
@@ -1,13 +1,12 @@
Nikola Metadata Upgrade (v7 to v8)
==================================

This is a plugin to upgrade metadata in `.meta` files from the old format
(without descriptions) to the new reST-esque format. It only applies to users
with two-file posts (`.meta` files alongside text) in the older format (up to 7
lines of text without any descriptions), used by Nikola before v8.0.0. If this
is the case on your site, **you will be warned** by `nikola build` — otherwise,
don’t install this plugin (it won’t do a thing anyway and will only waste disk
space and load time).
This is a plugin to upgrade old-style tags metadata (`draft`, `private`, `mathjax`)
to new-style metadata, i.e. using the `status` and `has_math` metadata fields. The
tags were used in Nikola v7 and earlier, and are no longer used by default in
Nikola v8. If you are using them in your blog, **you will be warned** by
`nikola build` — otherwise, don’t install this plugin (it won’t do a thing anyway
and will only waste disk space and load time).

The plugin adds the `nikola upgrade_metadata_v8` command. Remove the plugin
manually after the upgrade.
114 changes: 101 additions & 13 deletions v8/upgrade_metadata_v8/upgrade_metadata_v8.py
Expand Up @@ -28,6 +28,7 @@
from __future__ import unicode_literals
import io
import os
import sys
import nikola.post
from nikola.plugin_categories import Command
from nikola import utils
Expand All @@ -52,6 +53,11 @@ class UpgradeMetadata(Command):
def _execute(self, options, args):
L = utils.get_logger('upgrade_metadata_v8', utils.STDERR_HANDLER)

if not self.site.config['USE_TAG_METADATA']:
L.error('This plugin can only be used if USE_TAG_METADATA is set to True.')
sys.exit(-1)
self.site.config['WARN_ABOUT_TAG_METADATA'] = False

# scan posts
self.site.scan_posts()
flagged = []
Expand All @@ -64,30 +70,112 @@ def _execute(self, options, args):
else:
L.info('{0} posts (and/or their translations) contain old-style metadata:'.format(len(flagged)))
for post in flagged:
L.info(' ' + post.metadata_path)
L.info(' ' + (post.metadata_path if post.is_two_file else post.source_path))
L.warn('Please make a backup before running this plugin. It might eat your data.')
if not options['yes']:
yesno = utils.ask_yesno("Proceed with metadata upgrade?")
if options['yes'] or yesno:
no_converted = 0
no_converted_partial = 0
for post in flagged:
converted = False
fully_converted = True
for lang in self.site.config['TRANSLATIONS'].keys():
# Get file names and extractor
extractor = post.used_extractor[lang]
is_two_file = post.is_two_file
if lang == post.default_lang:
fname = post.metadata_path
fname = post.metadata_path if is_two_file else post.source_path
else:
meta_path = os.path.splitext(post.source_path)[0] + '.meta'
meta_path = os.path.splitext(post.source_path)[0] + '.meta' if is_two_file else post.source_path
fname = utils.get_translation_candidate(post.config, meta_path, lang)

if os.path.exists(fname):
with io.open(fname, 'r', encoding='utf-8') as fh:
meta = fh.readlines()
# We don't handle compilers which extract metadata for now
if post.compiler is extractor:
L.warn('Cannot convert {0} (language {1}), as metadata was extracted by compiler.'.format(fname, lang))
fully_converted = False
continue

# Read metadata and text from post file
with io.open(fname, "r", encoding="utf-8-sig") as meta_file:
source_text = meta_file.read()
if not is_two_file:
_, content_str = extractor.split_metadata_from_text(source_text)
meta = extractor.extract_text(source_text)

# Consider metadata mappings
sources = {
'tags': 'tags',
'status': 'status',
'has_math': 'has_math',
}
for foreign, ours in self.site.config.get('METADATA_MAPPING', {}).get(extractor.map_from, {}).items():
if ours in sources:
sources[ours] = foreign
for meta_key, hook in self.site.config.get('METADATA_VALUE_MAPPING', {}).get(extractor.map_from, {}).items():
if meta_key in sources.values():
L.warn('Cannot convert {0} (language {1}): a metadata value mapping is defined for "{2}"!'.format(fname, lang, meta_key))

# Update metadata
updated = False
tags = meta.get(sources['tags'], [])
tags_are_string = False
if not isinstance(tags, dict):
tags_are_string = True
tags = [tag.strip() for tag in tags.split(',') if tag.strip()]

if 'draft' in [_.lower() for _ in tags]:
tags.remove('draft')
meta[sources['status']] = 'draft'
updated = True

if 'private' in tags:
tags.remove('private')
meta[sources['status']] = 'private'
updated = True

if 'mathjax' in tags:
tags.remove('mathjax')
meta[sources['has_math']] = 'yes'
updated = True

if not meta[min(1, len(meta) - 1)].startswith('.. '):
# check if we’re dealing with old style metadata
with io.open(fname, 'w', encoding='utf-8') as fh:
for k, v in zip(self.fields, meta):
fh.write('.. {0}: {1}'.format(k, v))
L.debug(fname)
if tags_are_string:
meta[sources['tags']] = ', '.join(tags)

if not updated:
# Nothing to do (but successful)!
converted = True
continue

# Recombine metadata with post text if necessary, and write back to file
meta_str = extractor.write_metadata(meta)
print(meta_str)
if not is_two_file:
if extractor.name == 'nikola':
final_str = meta_str + '\n\n' + content_str
elif extractor.name == 'yaml':
final_str = meta_str + '\n---\n' + content_str
elif extractor.name == 'toml':
final_str = meta_str + '\n+++\n' + content_str
else:
L.error("Cannot convert {0} (language {1}): don't know how to recombine metadata with text for the {2} extractor!".format(fname, lang, extractor.name))
fully_converted = False
continue
else:
final_str = meta_str

with io.open(fname, "w", encoding="utf-8-sig") as meta_file:
meta_file.write(final_str)
converted = True

if converted:
if fully_converted:
no_converted += 1
else:
no_converted_partial += 1

L.info('{0} posts upgraded.'.format(len(flagged)))
L.info('{0} out of {2} posts upgraded; {1} only converted partially (see above output).'
.format(no_converted + no_converted_partial, no_converted_partial, len(flagged)))
else:
L.info('Metadata not upgraded.')
else:
Expand Down

0 comments on commit c94cff1

Please sign in to comment.