Skip to content

Instantly share code, notes, and snippets.

@punchagan
Last active December 7, 2019 05:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save punchagan/025b0fbf032dc20d0b36d35ec7bf5339 to your computer and use it in GitHub Desktop.
Save punchagan/025b0fbf032dc20d0b36d35ec7bf5339 to your computer and use it in GitHub Desktop.
Nikola to Hugo tools
#!/usr/bin/env python3
""" Script to convert a Nikola blog to Hugo
Requirements:
- toml
Usage:
./nikola-to-hugo.py /path/to/nikola/blog
"""
import os
from os.path import abspath, dirname, exists, join, sep
from shutil import copytree, rmtree
import subprocess
import sys
import toml
from nikola import Nikola
def nikola_site(path):
sys.path.insert(0, path)
import conf
site = Nikola(**conf.__dict__)
site.init_plugins()
site.scan_posts()
return site
def create_hugo_site(path):
hugo_path = '{}-hugo'.format(path.rstrip(sep))
subprocess.call(['hugo', 'new', 'site', hugo_path])
return hugo_path
def convert_blog(path):
site = nikola_site(path)
hugo_path = create_hugo_site(path)
update_conf(site.config, hugo_path)
for post in site.timeline:
convert_post(site, post, path, hugo_path)
copy_static_files(path, hugo_path)
def copy_static_files(path, hugo_path):
files = join(path, 'files')
static = join(hugo_path, 'static')
rmtree(static, ignore_errors=True)
copytree(files, static)
def update_conf(nikola_conf, hugo_path):
conf = join(hugo_path, 'config.toml')
with open(conf) as f:
hugo_config = toml.load(f)
hugo_config['baseurl'] = nikola_conf['BASE_URL']
hugo_config['title'] = nikola_conf['BLOG_TITLE']()
if nikola_conf['COMMENT_SYSTEM'] == 'disqus':
hugo_config['disqusShortname'] = nikola_conf['COMMENT_SYSTEM_ID']
with open(conf, 'w') as g:
toml.dump(hugo_config, g)
def get_post_content(site, src):
compiler = site.get_compiler(src)
with open(src) as f:
return compiler.split_metadata(f.read())[1]
def toml_metadata(post):
meta = post.meta['en']
if 'tags' in meta:
meta['tags'] = post.tags
if 'date' in meta:
meta['date'] = post.date
if 'updated' in meta:
meta['updated'] = post.updated
if post.is_draft or post.is_private:
meta['draft'] = True
meta['type'] = 'post' if post.is_post else 'page'
return toml.dumps(meta)
def convert_post(site, post, path, hugo_path):
src = join(path, post.source_path)
dst = join(hugo_path, 'content', post.source_path)
if not exists(dirname(dst)):
os.mkdir(dirname(dst))
meta = "+++\n{}\n+++\n\n".format(toml_metadata(post))
content = get_post_content(site, src)
with open(dst, 'w') as f:
f.write(meta)
f.write(content)
def main():
if len(sys.argv) != 2:
print(__doc__)
sys.exit(1)
path = abspath(sys.argv[1])
convert_blog(path)
if __name__ == '__main__':
main()
#!/usr/bin/env python3
""" Script to convert a Nikola blog to Hugo
Requirements:
- toml
Usage:
./nikola-to-ox-hugo.py /path/to/nikola/blog
"""
import os
from os.path import abspath, dirname, exists, join, sep
from shutil import copytree, rmtree
import subprocess
import sys
import toml
from nikola import Nikola
def nikola_site(path):
sys.path.insert(0, path)
import conf
site = Nikola(**conf.__dict__)
site.init_plugins()
site.scan_posts()
return site
def create_hugo_site(path):
hugo_path = '{}-hugo'.format(path.rstrip(sep))
subprocess.call(['hugo', 'new', 'site', hugo_path])
return hugo_path
def convert_blog(path):
site = nikola_site(path)
hugo_path = create_hugo_site(path)
update_conf(site.config, hugo_path)
convert_posts(site, path, hugo_path)
copy_static_files(path, hugo_path)
def copy_static_files(path, hugo_path):
files = join(path, 'files')
static = join(hugo_path, 'static')
rmtree(static, ignore_errors=True)
copytree(files, static)
def update_conf(nikola_conf, hugo_path):
conf = join(hugo_path, 'config.toml')
with open(conf) as f:
hugo_config = toml.load(f)
hugo_config['baseurl'] = nikola_conf['BASE_URL']
hugo_config['title'] = nikola_conf['BLOG_TITLE']()
if nikola_conf['COMMENT_SYSTEM'] == 'disqus':
hugo_config['disqusShortname'] = nikola_conf['COMMENT_SYSTEM_ID']
with open(conf, 'w') as g:
toml.dump(hugo_config, g)
def get_post_content(site, src):
compiler = site.get_compiler(src)
with open(src) as f:
return compiler.split_metadata(f.read())[1]
def get_headline_with_properties(post):
state = 'DRAFT' if post.is_draft or post.is_private else 'DONE'
tags = ':{}:'.format(':'.join(post.tags)) if post.tags else ''
headline = '* {} {} {}\n'.format(state, post.title(), tags)
properties = {
'EXPORT_FILE_NAME': post.meta('slug'),
'EXPORT_DATE': post.date.isoformat(),
}
properties = ':PROPERTIES:\n{}\n:END:\n'.format(
'\n'.join(':{}: {}'.format(key, value)
for key, value in properties.items())
)
return '{}{}'.format(headline, properties)
def convert_posts(site, path, hugo_path):
content_dir = join(hugo_path, 'content-org')
if not exists(content_dir):
os.mkdir(content_dir)
post_content = []
for post in site.timeline:
src = join(path, post.source_path)
headline = get_headline_with_properties(post)
content = get_post_content(site, src)
post_content.append('{}\n{}'.format(headline, content))
out = join(content_dir, 'all-posts.org')
with open(out, 'w') as f:
f.write('#+STARTUP: indent\n')
f.write('#+HUGO_BASE_DIR: {}\n'.format(hugo_path))
f.write('#+SEQ_TODO: TODO DRAFT DONE\n\n')
f.write('\n\n'.join(post_content))
def main():
if len(sys.argv) != 2:
print(__doc__)
sys.exit(1)
path = abspath(sys.argv[1])
convert_blog(path)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment