Github Pages を Sphinx で¶
2015/04/19
GitHub Pages というシステムがある。これは、 GitHub に <username>.github.io といったプロジェクトを作成すると、そこに配置したファイルがこの URL で公開されるサービスとなっている。
Python には Sphinx (日本語) といったドキュメンテーションツールがあるので、使えないかと思い試した。
結果使えそうなので、以下に流れをまとめる。
細かい点は github のリポジトリ をみてください。
tl;dr¶
ソースと jptomo.github.io のリポジトリを分割した。
GitHub Pages では _static などのアンダーバー始まりのディレクトリは 公開できないので、 Sphinx の実行時にパッチを当てるようにした。
CSS を追加した。
サイドバーのリンクを書き換えた。
日付けのロール my_date を作成した。
ソースコード分割¶
GitHub Pages ではリポジトリ直下の index.html が先ず表示される。
Sphinx で make html したものがリポジトリ直下に欲しかった。
これを解決するため、記事のソースコードと、 GitHub Pages のコードを分けた。
記事のソースコード: jptomo/github-pages
アンダーバー対策¶
GitHub Pages では、アンダーバーを接頭辞として持つディレクトリを公開できない。
Sphinx は標準では _static/ などのディレクトリに CSSファイルを書き出すので、対策が必要。
tk0miya さんのロール作成サンプルがあったので 流用させていただきました。ありがとうございます。
sphinxcontrib_staticdir_hack.py (gist)
以下コード (github):
# -*- coding: utf-8 -*-
#
# Sphinx extension for renaming _static/ directory
#
# Author: Takeshi KOMIYA / License: BSD
#
import re
import os
import shutil
NEW_STATIC_NAME = 'static/'
NEW_SOURCES_NAME = 'sources/'
def on_builder_inited(app):
if app.builder.name == 'html':
for old, new in [('_static', NEW_STATIC_NAME),
('_source', NEW_SOURCES_NAME)]:
replacer = (lambda uri: re.sub(r'^{}/'.format(old), new, uri))
for i, f in enumerate(app.builder.script_files):
app.builder.script_files[i] = replacer(f)
for i, f in enumerate(app.builder.css_files):
app.builder.css_files[i] = replacer(f)
def on_html_page_context(app, pagename, templatename, context, doctree):
original_pathto = context['pathto']
def pathto(otheruri, *args, **kwargs):
otheruri = re.sub(r'^_static/', NEW_STATIC_NAME, otheruri)
otheruri = re.sub(r'^_sources/', NEW_SOURCES_NAME, otheruri)
return original_pathto(otheruri, *args, **kwargs)
context['pathto'] = pathto
def on_build_finished(app, exception):
if app.builder.name == 'html' and exception is None:
for old, new in [('_static', NEW_STATIC_NAME),
('_sources', NEW_SOURCES_NAME)]:
old_dir = os.path.join(app.outdir, old)
new_dir = os.path.join(app.outdir, new)
if os.path.exists(old_dir):
if os.path.exists(new_dir):
shutil.rmtree(new_dir)
shutil.move(old_dir, new_dir)
def setup(app):
app.connect('builder-inited', on_builder_inited)
app.connect('html-page-context', on_html_page_context)
app.connect('build-finished', on_build_finished)
CSS 追加¶
Sphinx のテーマは組込の alabaster (github) を利用した。
ただ、サイドバーを右側に寄せたかったので、 CSSを追加し、文章とサイドバーの位置を逆にした。
conf.py の末尾に以下の記載をする。
def setup(app):
app.add_stylesheet('style.css')
その上で、以下のCSS (github) を _static/ 配下に配置する。
@charset "utf-8";
div.bodywrapper {
margin: 0;
width: 730px;
}
div.sphinxsidebar {
float: right;
width: 230px;
}
サイドバー修正¶
標準の前の記事、次の記事、を少し書き換えて、 Top ページへのリンクにしたかった。
先ずは、 conf.py の以下の設定を書き換える。
html_sidebars = {
'**': [
'side_index.html',
'searchbox.html',
'side_genindex.html',
]
}
後は、先程追加した html ファイルを _templates 配下に作成すれば良い。
以下は作成したもの。 なお、 searchbox.html は組込である。
日付のロール作成¶
ブログタイトル直下の日付を my_date といったロールを作成して、作りたかった。
またまた tk0miya さんのロール作成サンプルがあったので 流用させていただきました。ありがとうございます。
以下コード (github):
# -*- coding: utf-8 -*-
import os
from textwrap import dedent
from docutils.parsers.rst import roles
def on_builder_inited(app):
roles.register_local_role(
'my_date',
roles.CustomRole(
'my_date',
roles.generic_custom_role,
{'class': ['my_date']}, []))
def on_html_collect_pages(app):
cssdir = os.path.join(app.builder.outdir, '_static')
cssfile = os.path.join(cssdir, 'roles.css')
if not os.path.exists(cssdir):
os.makedirs(cssdir)
with open(cssfile, 'w') as fp:
fp.write(dedent('''
@charset "utf-8";
span.my_date {
display: block;
text-align: right;
padding-right: 1em;
}
''').strip())
return ()
def html_page_context(app, pagename, templatename, context, doctree):
if 'css_files' in context:
context['css_files'].append('_static/roles.css')
def setup(app):
app.connect("builder-inited", on_builder_inited)
app.connect("html-collect-pages", on_html_collect_pages)
app.connect("html-page-context", html_page_context)
終わりに¶
Google アナリティクス や各種ソーシャルボタン、コメント機能 (DISQUS) をつけたい。そのうち、そのうちね。