Switch to Sphinx 1.0 to generate User Manual

This commit is contained in:
Kovid Goyal 2010-07-25 13:27:55 -06:00
parent a69641ac1b
commit 48df7c38bd
7 changed files with 64 additions and 313 deletions

View File

@ -73,11 +73,11 @@ class Manual(Command):
os.makedirs(d) os.makedirs(d)
if not os.path.exists('.build'+os.sep+'html'): if not os.path.exists('.build'+os.sep+'html'):
os.makedirs('.build'+os.sep+'html') os.makedirs('.build'+os.sep+'html')
os.environ['__appname__']= __appname__ os.environ['__appname__'] = __appname__
os.environ['__version__']= __version__ os.environ['__version__'] = __version__
subprocess.check_call(['sphinx-build', '-b', 'custom', '-t', 'online', subprocess.check_call(['sphinx-build', '-b', 'html', '-t', 'online',
'-d', '.build/doctrees', '.', '.build/html']) '-d', '.build/doctrees', '.', '.build/html'])
subprocess.check_call(['sphinx-build', '-b', 'epub', '-d', subprocess.check_call(['sphinx-build', '-b', 'myepub', '-d',
'.build/doctrees', '.', '.build/epub']) '.build/doctrees', '.', '.build/epub'])
shutil.copyfile(self.j('.build', 'epub', 'calibre.epub'), self.j('.build', shutil.copyfile(self.j('.build', 'epub', 'calibre.epub'), self.j('.build',
'html', 'calibre.epub')) 'html', 'calibre.epub'))

View File

@ -37,7 +37,7 @@ qthelp:
epub: epub:
mkdir -p .build/qthelp .build/doctrees mkdir -p .build/qthelp .build/doctrees
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) .build/epub $(SPHINXBUILD) -b myepub $(ALLSPHINXOPTS) .build/epub
@echo @echo
@echo "Build finished." @echo "Build finished."

View File

@ -23,9 +23,11 @@ custom
# General configuration # General configuration
# --------------------- # ---------------------
needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions # Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.addons.*') or your custom ones. # coming with Sphinx (named 'sphinx.addons.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'custom'] extensions = ['sphinx.ext.autodoc', 'custom', 'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['templates'] templates_path = ['templates']
@ -36,6 +38,9 @@ source_suffix = '.rst'
# The master toctree document. # The master toctree document.
master_doc = 'index' master_doc = 'index'
# The language
language = 'en'
# General substitutions. # General substitutions.
project = __appname__ project = __appname__
copyright = '2008, Kovid Goyal' copyright = '2008, Kovid Goyal'
@ -81,7 +86,6 @@ pygments_style = 'sphinx'
# given in html_static_path. # given in html_static_path.
html_theme = 'default' html_theme = 'default'
html_theme_options = {'stickysidebar':'true', 'relbarbgcolor':'black'} html_theme_options = {'stickysidebar':'true', 'relbarbgcolor':'black'}
html_style = 'calibre.css'
# Add any paths that contain custom static files (such as style sheets) here, # Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,
@ -100,8 +104,16 @@ html_use_smartypants = True
html_title = 'calibre User Manual' html_title = 'calibre User Manual'
html_short_title = 'Start' html_short_title = 'Start'
html_logo = 'resources/logo.png' html_logo = 'resources/logo.png'
epub_author = 'Kovid Goyal' epub_author = 'Kovid Goyal'
epub_cover = 'resources/epub_cover.jpg' epub_cover = 'epub_cover.jpg'
epub_publisher = 'Kovid Goyal'
epub_identifier = 'http://calibre-ebook.com/user_manual'
epub_scheme = 'url'
epub_uid = 'S54a88f8e9d42455e9c6db000e989225f'
epub_tocdepth = 4
epub_tocdup = True
epub_pre_files = [('epub_titlepage.html', 'Cover')]
# Custom sidebar templates, maps document names to template names. # Custom sidebar templates, maps document names to template names.
#html_sidebars = {} #html_sidebars = {}

View File

@ -9,9 +9,6 @@ sys.path.insert(0, os.path.abspath('../../'))
sys.extensions_location = '../plugins' sys.extensions_location = '../plugins'
sys.resources_location = '../../../resources' sys.resources_location = '../../../resources'
from sphinx.builders.html import StandaloneHTMLBuilder
from qthelp import QtHelpBuilder
from epub import EPUBHelpBuilder
from sphinx.util import rpartition from sphinx.util import rpartition
from sphinx.util.console import bold from sphinx.util.console import bold
from sphinx.ext.autodoc import prepare_docstring from sphinx.ext.autodoc import prepare_docstring
@ -20,12 +17,7 @@ from docutils import nodes
sys.path.append(os.path.abspath('../../../')) sys.path.append(os.path.abspath('../../../'))
from calibre.linux import entry_points from calibre.linux import entry_points
from epub import EPUBHelpBuilder
class CustomBuilder(StandaloneHTMLBuilder):
name = 'custom'
class CustomQtBuild(QtHelpBuilder):
name = 'customqt'
def substitute(app, doctree): def substitute(app, doctree):
pass pass
@ -305,9 +297,6 @@ def auto_member(dirname, arguments, options, content, lineno,
def setup(app): def setup(app):
app.add_config_value('epub_cover', None, False) app.add_config_value('epub_cover', None, False)
app.add_config_value('epub_author', '', False)
app.add_builder(CustomBuilder)
app.add_builder(CustomQtBuild)
app.add_builder(EPUBHelpBuilder) app.add_builder(EPUBHelpBuilder)
app.add_directive('automember', auto_member, 1, (1, 0, 1)) app.add_directive('automember', auto_member, 1, (1, 0, 1))
app.connect('doctree-read', substitute) app.connect('doctree-read', substitute)

View File

@ -6,75 +6,19 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os, mimetypes, uuid, shutil import os, time
from datetime import datetime
from docutils import nodes
from xml.sax.saxutils import escape, quoteattr
from urlparse import urldefrag
from zipfile import ZipFile, ZIP_STORED, ZipInfo
from sphinx import addnodes from sphinx.builders.epub import EpubBuilder
from sphinx.builders.html import StandaloneHTMLBuilder
NCX = '''\ class EPUBHelpBuilder(EpubBuilder):
<?xml version="1.0" encoding="UTF-8"?> name = 'myepub'
<ncx version="2005-1"
xml:lang="en"
xmlns="http://www.daisy.org/z3986/2005/ncx/"
xmlns:calibre="http://calibre.kovidgoyal.net/2009/metadata"
>
<head>
<meta name="dtb:uid" content="{uid}"/>
<meta name="dtb:depth" content="{depth}"/>
<meta name="dtb:generator" content="sphinx"/>
<meta name="dtb:totalPageCount" content="0"/>
<meta name="dtb:maxPageNumber" content="0"/>
</head>
<docTitle><text>Table of Contents</text></docTitle>
<navMap>
{navpoints}
</navMap>
</ncx>
'''
OPF = '''\ def add_cover(self, outdir, cover_fname):
<?xml version="1.0" encoding="UTF-8"?> href = '_static/'+cover_fname
<package version="2.0" opf = os.path.join(self.outdir, 'content.opf')
xmlns="http://www.idpf.org/2007/opf"
unique-identifier="sphinx_id"
>
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf" xmlns:calibre="http://calibre.kovidgoyal.net/2009/metadata">
<dc:title>{title}</dc:title>
<dc:creator opf:role="aut">{author}</dc:creator>
<dc:contributor opf:role="bkp">Sphinx</dc:contributor>
<dc:identifier opf:scheme="sphinx" id="sphinx_id">{uid}</dc:identifier>
<dc:date>{date}</dc:date>
<meta name="calibre:publication_type" content="sphinx_manual" />
<meta name="cover" content="cover"/>
</metadata>
<manifest>
{manifest}
</manifest>
<spine toc="ncx">
{spine}
</spine>
<guide>
{guide}
</guide>
</package>
'''
CONTAINER='''\ cover = '''\
<?xml version="1.0"?> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
<rootfiles>
<rootfile full-path="{0}" media-type="application/oebps-package+xml"/>
</rootfiles>
</container>
'''
SVG_TEMPLATE = '''\
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="calibre:cover" content="true" /> <meta name="calibre:cover" content="true" />
@ -92,212 +36,23 @@ SVG_TEMPLATE = '''\
<image width="600" height="800" xlink:href="%s"/> <image width="600" height="800" xlink:href="%s"/>
</svg> </svg>
</body> </body>
</html> </html>
''' '''%href
self.files.append('epub_titlepage.html')
class TOC(list): open(os.path.join(outdir, self.files[-1]), 'wb').write(cover)
def __init__(self, title=None, href=None):
list.__init__(self)
self.title, self.href = title, href
def create_child(self, title, href):
self.append(TOC(title, href))
return self[-1]
def depth(self):
try:
return max(node.depth() for node in self)+1
except ValueError:
return 1
class EPUBHelpBuilder(StandaloneHTMLBuilder): raw = open(opf, 'rb').read()
""" raw = raw.replace('</metadata>',
Builder that also outputs Qt help project, contents and index files. ('<meta name="cover" content="%s"/>\n'
""" '<dc:date>%s</dc:date>\n</metadata>') %
name = 'epub' (href.replace('/', '_'), time.strftime('%Y-%m-%d')))
raw = raw.replace('</manifest>',
# don't copy the reST source ('<item id="{0}" href="{0}" media-type="application/xhtml+xml"/>\n</manifest>').\
copysource = False format('epub_titlepage.html'))
open(opf, 'wb').write(raw)
supported_image_types = ['image/svg+xml', 'image/png', 'image/gif',
'image/jpeg']
# don't add links
add_permalinks = False
# don't add sidebar etc.
embedded = True
def init(self):
StandaloneHTMLBuilder.init(self)
self.out_suffix = '.html'
self.link_suffix = '.html'
self.html_outdir = self.outdir = os.path.join(self.outdir, 'src')
self.conf = self.config
def finish(self):
StandaloneHTMLBuilder.finish(self)
self.create_titlepage()
self.outdir = os.path.dirname(self.outdir)
cwd = os.getcwd()
os.chdir(self.html_outdir)
try:
self.generate_manifest()
self.generate_toc()
self.render_opf()
self.render_epub()
finally:
os.chdir(cwd)
def render_epub(self):
container = CONTAINER.format('content.opf')
path = os.path.abspath('..'+os.sep+self.conf.project+'.epub')
zf = ZipFile(path, 'w')
zi = ZipInfo('mimetype')
zi.compress_type = ZIP_STORED
zf.writestr(zi, 'application/epub+zip')
zf.writestr('META-INF/container.xml', container)
for url in self.manifest:
fp = os.path.join(self.html_outdir, *url.split('/'))
zf.write(fp, url)
zf.close()
self.info('EPUB created at: '+path)
def render_opf(self):
manifest = []
for href in self.manifest:
mt, id = self.manifest[href]
manifest.append(' '*8 + '<item id=%s href=%s media-type=%s />'%\
tuple(map(quoteattr, (id, href, mt))))
manifest = '\n'.join(manifest)
spine = [' '*8+'<itemref idref=%s />'%quoteattr(x) for x in self.spine]
spine = '\n'.join(spine)
guide = ''
opf = OPF.format(title=escape(self.conf.html_title),
author=escape(self.conf.epub_author), uid=str(uuid.uuid4()),
date=datetime.now().isoformat(), manifest=manifest, spine=spine,
guide=guide)
open('content.opf', 'wb').write(opf)
self.manifest['content.opf'] = ('application/oebps-package+xml', 'opf')
def create_titlepage(self):
self.cover_image_url = None
if self.conf.epub_cover:
img = '_static/'+os.path.basename(self.conf.epub_cover)
shutil.copyfile(self.conf.epub_cover, os.path.join(self.html_outdir,
*img.split('/')))
self.cover_image_url = img
tp = SVG_TEMPLATE%img.split('/')[-1]
open(os.path.join(self.html_outdir, '_static', 'titlepage.html'),
'wb').write(tp)
def generate_manifest(self):
self.manifest = {}
id = 1
for dirpath, dirnames, filenames in os.walk('.'):
for fname in filenames:
if fname == '.buildinfo':
continue
fpath = os.path.abspath(os.path.join(dirpath, fname))
url = os.path.relpath(fpath).replace(os.sep, '/')
self.manifest[url] = mimetypes.guess_type(url, False)[0]
if self.manifest[url] is None:
self.warn('Unknown mimetype for: ' + url)
self.manifest[url] = 'application/octet-stream'
if self.manifest[url] == 'text/html':
self.manifest[url] = 'application/xhtml+xml'
if self.cover_image_url and url.endswith(self.cover_image_url):
id_ = 'cover'
else:
id_ = 'id'+str(id)
id += 1
self.manifest[url] = (self.manifest[url], id_)
def isdocnode(self, node):
if not isinstance(node, nodes.list_item):
return False
if len(node.children) != 2:
return False
if not isinstance(node.children[0], addnodes.compact_paragraph):
return False
if not isinstance(node.children[0][0], nodes.reference):
return False
if not isinstance(node.children[1], nodes.bullet_list):
return False
return True
def generate_toc(self):
tocdoc = self.env.get_and_resolve_doctree(self.config.master_doc, self,
prune_toctrees=False)
istoctree = lambda node: (
isinstance(node, addnodes.compact_paragraph)
and node.has_key('toctree'))
toc = TOC()
for node in tocdoc.traverse(istoctree):
self.extend_toc(toc, node)
self._parts = []
self._po = 0
self._po_map = {}
self.spine_map = {}
self.spine = []
self.render_toc(toc)
navpoints = '\n'.join(self._parts).strip()
ncx = NCX.format(uid=str(uuid.uuid4()), depth=toc.depth(),
navpoints=navpoints)
open('toc.ncx', 'wb').write(ncx)
self.manifest['toc.ncx'] = ('application/x-dtbncx+xml', 'ncx')
self.spine.insert(0, self.manifest[self.conf.master_doc+'.html'][1])
if self.conf.epub_cover:
self.spine.insert(0, self.manifest['_static/titlepage.html'][1])
def add_to_spine(self, href):
href = urldefrag(href)[0]
if href not in self.spine_map:
for url in self.manifest:
if url == href:
self.spine_map[href]= self.manifest[url][1]
self.spine.append(self.spine_map[href])
def render_toc(self, toc, level=2):
for child in toc:
if child.title and child.href:
href = child.href
self.add_to_spine(href)
title = escape(child.title)
if isinstance(title, unicode):
title = title.encode('utf-8')
if child.href in self._po_map:
po = self._po_map[child.href]
else:
self._po += 1
po = self._po
self._parts.append(' '*(level*4)+
'<navPoint id="%s" playOrder="%d">'%(uuid.uuid4(),
po))
self._parts.append(' '*((level+1)*4)+
'<navLabel><text>%s</text></navLabel>'%title)
self._parts.append(' '*((level+1)*4)+
'<content src=%s />'%quoteattr(href))
self.render_toc(child, level+1)
self._parts.append(' '*(level*4)+'</navPoint>')
def extend_toc(self, toc, node):
if self.isdocnode(node):
refnode = node.children[0][0]
parent = toc.create_child(refnode.astext(), refnode['refuri'])
for subnode in node.children[1]:
self.extend_toc(parent, subnode)
elif isinstance(node, (nodes.list_item, nodes.bullet_list,
addnodes.compact_paragraph)):
for subnode in node:
self.extend_toc(toc, subnode)
elif isinstance(node, nodes.reference):
parent = toc.create_child(node.astext(), node['refuri'])
def build_epub(self, outdir, *args, **kwargs):
if self.config.epub_cover:
self.add_cover(outdir, self.config.epub_cover)
EpubBuilder.build_epub(self, outdir, *args, **kwargs)

View File

@ -1,5 +0,0 @@
@import url("default.css");
table.docutils td, table.docutils th { padding: 1em; border-bottom: 0; }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 10 KiB