diff options
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | doc/builders.rst | 24 | ||||
-rw-r--r-- | doc/config.rst | 164 | ||||
-rw-r--r-- | doc/invocation.rst | 5 | ||||
-rw-r--r-- | sphinx/builders/__init__.py | 1 | ||||
-rw-r--r-- | sphinx/builders/applehelp.py | 261 | ||||
-rw-r--r-- | sphinx/builders/html.py | 34 | ||||
-rw-r--r-- | sphinx/builders/htmlhelp.py | 3 | ||||
-rw-r--r-- | sphinx/config.py | 33 | ||||
-rw-r--r-- | sphinx/environment.py | 2 | ||||
-rw-r--r-- | sphinx/quickstart.py | 12 | ||||
-rw-r--r-- | tests/root/conf.py | 3 | ||||
-rw-r--r-- | tests/root/en.lproj/localized.txt | 2 | ||||
-rw-r--r-- | tests/test_build.py | 7 | ||||
-rw-r--r-- | tests/test_build_applehelp.py | 56 |
16 files changed, 591 insertions, 19 deletions
@@ -14,6 +14,7 @@ Other co-maintainers: Other contributors, listed alphabetically, are: +* Alastair Houghton -- Apple Help builder * Andi Albrecht -- agogo theme * Henrique Bastos -- SVG support for graphviz extension * Daniel Bültmann -- todo extension @@ -20,6 +20,8 @@ Features added suffixes. * Add the ability to specify source parsers by source suffix with the :confval:`source_parsers` config value. +* #1675: A new builder, AppleHelpBuilder, has been added that builds Apple + Help Books. Bugs fixed ---------- diff --git a/doc/builders.rst b/doc/builders.rst index 3c6f6b982..4fbd5bae6 100644 --- a/doc/builders.rst +++ b/doc/builders.rst @@ -76,6 +76,30 @@ The builder's "name" must be given to the **-b** command-line option of .. _Qt help: http://qt-project.org/doc/qt-4.8/qthelp-framework.html +.. module:: sphinx.builders.applehelp +.. class:: AppleHelpBuilder + + This builder produces an Apple Help Book based on the same output as the + standalone HTML builder. + + If the source directory contains any ``.lproj`` folders, the one + corresponding to the selected language will have its contents merged with + the generated output. These folders will be ignored by all other + documentation types. + + In order to generate a valid help book, this builder requires the command + line tool :program:`hiutil`, which is only available on Mac OS X 10.6 and + above. You can disable the indexing step by setting + :confval:`applehelp_disable_external_tools` to ``True``, in which case the + output will not be valid until :program:`hiutil` has been run on all of the + ``.lproj`` folders within the bundle. + + .. autoattribute:: name + + .. autoattribute:: supported_image_types + + .. versionadded:: 1.3 + .. module:: sphinx.builders.devhelp .. class:: DevhelpBuilder diff --git a/doc/config.rst b/doc/config.rst index eea64ff01..0219a9ee0 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -929,6 +929,170 @@ that use Sphinx's HTMLWriter class. Output file base name for HTML help builder. Default is ``'pydoc'``. +.. _applehelp-options: + +Options for Apple Help output +----------------------------- + +.. versionadded:: 1.3 + +These options influence the Apple Help output. This builder derives from the +HTML builder, so the HTML options also apply where appropriate. + +.. note:: + + Apple Help output will only work on Mac OS X 10.6 and higher, as it + requires the :program:`hiutil` and :program:`codesign` command line tools, + neither of which are Open Source. + + You can disable the use of these tools using + :confval:`applehelp_disable_external_tools`, but the result will not be a + valid help book until the indexer is run over the ``.lproj`` folders within + the bundle. + +.. confval:: applehelp_bundle_name + + The basename for the Apple Help Book. Defaults to the :confval:`project` + name. + +.. confval:: applehelp_bundle_id + + The bundle ID for the help book bundle. + + .. warning:: + + You *must* set this value in order to generate Apple Help. + +.. confval:: applehelp_dev_region + + The development region. Defaults to ``'en-us'``, which is Apple’s + recommended setting. + +.. confval:: applehelp_bundle_version + + The bundle version (as a string). Defaults to ``'1'``. + +.. confval:: applehelp_icon + + The help bundle icon file, or ``None`` for no icon. According to Apple’s + documentation, this should be a 16-by-16 pixel version of the application’s + icon with a transparent background, saved as a PNG file. + +.. confval:: applehelp_kb_product + + The product tag for use with :confval:`applehelp_kb_url`. Defaults to + :samp:`'{<project>}-{<release>}'`. + +.. confval:: applehelp_kb_url + + The URL for your knowledgebase server, + e.g. ``https://example.com/kbsearch.py?p='product'&q='query'&l='lang'``. + Help Viewer will replace the values ``'product'``, ``'query'`` and + ``'lang'`` at runtime with the contents of :confval:`applehelp_kb_product`, + the text entered by the user in the search box and the user’s system + language respectively. + + Defaults to ``None`` for no remote search. + +.. confval:: applehelp_remote_url + + The URL for remote content. You can place a copy of your Help Book’s + ``Resources`` folder at this location and Help Viewer will attempt to use + it to fetch updated content. + + e.g. if you set it to ``https://example.com/help/Foo/`` and Help Viewer + wants a copy of ``index.html`` for an English speaking customer, it will + look at ``https://example.com/help/Foo/en.lproj/index.html``. + + Defaults to ``None`` for no remote content. + +.. confval:: applehelp_index_anchors + + If ``True``, tell the help indexer to index anchors in the generated HTML. + This can be useful for jumping to a particular topic using the + ``AHLookupAnchor`` function or the ``openHelpAnchor:inBook:`` method in + your code. It also allows you to use ``help:anchor`` URLs; see the Apple + documentation for more information on this topic. + +.. confval:: applehelp_min_term_length + + Controls the minimum term length for the help indexer. Defaults to + ``None``, which means the default will be used. + +.. confval:: applehelp_stopwords + + Either a language specification (to use the built-in stopwords), or the + path to a stopwords plist, or ``None`` if you do not want to use stopwords. + The default stopwords plist can be found at + ``/usr/share/hiutil/Stopwords.plist`` and contains, at time of writing, + stopwords for the following languages: + + ========= ==== + Language Code + ========= ==== + English en + German de + Spanish es + French fr + Swedish sv + Hungarian hu + Italian it + ========= ==== + + Defaults to :confval:`language`, or if that is not set, to :confval:`en`. + +.. confval:: applehelp_locale + + Specifies the locale to generate help for. This is used to determine + the name of the ``.lproj`` folder inside the Help Book’s ``Resources``, and + is passed to the help indexer. + + Defaults to :confval:`language`, or if that is not set, to :confval:`en`. + +.. confval:: applehelp_title + + Specifies the help book title. Defaults to :samp:`'{<project>} Help'`. + +.. confval:: applehelp_codesign_identity + + Specifies the identity to use for code signing, or ``None`` if code signing + is not to be performed. + + Defaults to the value of the environment variable ``CODE_SIGN_IDENTITY``, + which is set by Xcode for script build phases, or ``None`` if that variable + is not set. + +.. confval:: applehelp_codesign_flags + + A *list* of additional arguments to pass to :program:`codesign` when + signing the help book. + + Defaults to a list based on the value of the environment variable + ``OTHER_CODE_SIGN_FLAGS``, which is set by Xcode for script build phases, + or the empty list if that variable is not set. + +.. confval:: applehelp_indexer_path + + The path to the :program:`hiutil` program. Defaults to + ``'/usr/bin/hiutil'``. + +.. confval:: applehelp_codesign_path + + The path to the :program:`codesign` program. Defaults to + ``'/usr/bin/codesign'``. + +.. confval:: applehelp_disable_external_tools + + If ``True``, the builder will not run the indexer or the code signing tool, + no matter what other settings are specified. + + This is mainly useful for testing, or where you want to run the Sphinx + build on a non-Mac OS X platform and then complete the final steps on OS X + for some reason. + + Defaults to ``False``. + + .. _epub-options: Options for epub output diff --git a/doc/invocation.rst b/doc/invocation.rst index e08fbb1bc..1d0c613c3 100644 --- a/doc/invocation.rst +++ b/doc/invocation.rst @@ -172,6 +172,11 @@ The :program:`sphinx-build` script has several options: Build HTML files with additional information for building a documentation collection in one of these formats. + **applehelp** + Build an Apple Help Book. Requires :program:`hiutil` and + :program:`codesign`, which are not Open Source and presently only + available on Mac OS X 10.6 and higher. + **latex** Build LaTeX sources that can be compiled to a PDF document using :program:`pdflatex`. diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index 72c27c307..2a28fd1c4 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -449,6 +449,7 @@ BUILTIN_BUILDERS = { 'htmlhelp': ('htmlhelp', 'HTMLHelpBuilder'), 'devhelp': ('devhelp', 'DevhelpBuilder'), 'qthelp': ('qthelp', 'QtHelpBuilder'), + 'applehelp': ('applehelp', 'AppleHelpBuilder'), 'epub': ('epub', 'EpubBuilder'), 'latex': ('latex', 'LaTeXBuilder'), 'text': ('text', 'TextBuilder'), diff --git a/sphinx/builders/applehelp.py b/sphinx/builders/applehelp.py new file mode 100644 index 000000000..5f2f061f5 --- /dev/null +++ b/sphinx/builders/applehelp.py @@ -0,0 +1,261 @@ +# -*- coding: utf-8 -*- +""" + sphinx.builders.applehelp + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + Build Apple help books. + + :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" +from __future__ import print_function + +import os +import codecs +import errno +import pipes + +from os import path + +from sphinx.builders.html import StandaloneHTMLBuilder +from sphinx.util import copy_static_entry +from sphinx.util.osutil import copyfile, ensuredir, os_path +from sphinx.util.console import bold +from sphinx.util.pycompat import htmlescape +from sphinx.util.matching import compile_matchers +from sphinx.errors import SphinxError + +import plistlib +import subprocess + + +# Use plistlib.dump in 3.4 and above +try: + write_plist = plistlib.dump +except AttributeError: + write_plist = plistlib.writePlist + + +# False access page (used because helpd expects strict XHTML) +access_page_template = '''\ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>%(title)s</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <meta name="robots" content="noindex" /> + <meta http-equiv="refresh" content="0;url=%(toc)s" /> + </head> + <body> + </body> +</html> +''' + + +class AppleHelpIndexerFailed(SphinxError): + category = 'Help indexer failed' + + +class AppleHelpCodeSigningFailed(SphinxError): + category = 'Code signing failed' + + +class AppleHelpBuilder(StandaloneHTMLBuilder): + """ + Builder that outputs an Apple help book. Requires Mac OS X as it relies + on the ``hiutil`` command line tool. + """ + name = 'applehelp' + + # don't copy the reST source + copysource = False + supported_image_types = ['image/png', 'image/gif', 'image/jpeg', + 'image/tiff', 'image/jp2', 'image/svg+xml'] + + # don't add links + add_permalinks = False + + # this is an embedded HTML format + embedded = True + + # don't generate the search index or include the search page + search = False + + def init(self): + super(AppleHelpBuilder, self).init() + # the output files for HTML help must be .html only + self.out_suffix = '.html' + + if self.config.applehelp_bundle_id is None: + raise SphinxError('You must set applehelp_bundle_id before ' \ + 'building Apple Help output') + + self.bundle_path = path.join(self.outdir, + self.config.applehelp_bundle_name \ + + '.help') + self.outdir = path.join(self.bundle_path, + 'Contents', + 'Resources', + self.config.applehelp_locale + '.lproj') + + def handle_finish(self): + super(AppleHelpBuilder, self).handle_finish() + + self.finish_tasks.add_task(self.copy_localized_files) + self.finish_tasks.add_task(self.build_helpbook) + + def copy_localized_files(self): + source_dir = path.join(self.confdir, + self.config.applehelp_locale + '.lproj') + target_dir = self.outdir + + if path.isdir(source_dir): + self.info(bold('copying localized files... '), nonl=True) + + ctx = self.globalcontext.copy() + matchers = compile_matchers(self.config.exclude_patterns) + copy_static_entry(source_dir, target_dir, self, ctx, + exclude_matchers=matchers) + + self.info('done') + + def build_helpbook(self): + contents_dir = path.join(self.bundle_path, 'Contents') + resources_dir = path.join(contents_dir, 'Resources') + language_dir = path.join(resources_dir, + self.config.applehelp_locale + '.lproj') + + for d in [contents_dir, resources_dir, language_dir]: + ensuredir(d) + + # Construct the Info.plist file + toc = self.config.master_doc + self.out_suffix + + info_plist = { + 'CFBundleDevelopmentRegion': self.config.applehelp_dev_region, + 'CFBundleIdentifier': self.config.applehelp_bundle_id, + 'CFBundleInfoDictionaryVersion': '6.0', + 'CFBundlePackageType': 'BNDL', + 'CFBundleShortVersionString': self.config.release, + 'CFBundleSignature': 'hbwr', + 'CFBundleVersion': self.config.applehelp_bundle_version, + 'HPDBookAccessPath': '_access.html', + 'HPDBookIndexPath': 'search.helpindex', + 'HPDBookTitle': self.config.applehelp_title, + 'HPDBookType': '3', + 'HPDBookUsesExternalViewer': False, + } + + if self.config.applehelp_icon is not None: + info_plist['HPDBookIconPath'] \ + = path.basename(self.config.applehelp_icon) + + if self.config.applehelp_kb_url is not None: + info_plist['HPDBookKBProduct'] = self.config.applehelp_kb_product + info_plist['HPDBookKBURL'] = self.config.applehelp_kb_url + + if self.config.applehelp_remote_url is not None: + info_plist['HPDBookRemoteURL'] = self.config.applehelp_remote_url + + self.info(bold('writing Info.plist... '), nonl=True) + with open(path.join(contents_dir, 'Info.plist'), 'wb') as f: + write_plist(info_plist, f) + self.info('done') + + # Copy the icon, if one is supplied + if self.config.applehelp_icon: + self.info(bold('copying icon... '), nonl=True) + + try: + copyfile(path.join(self.srcdir, self.config.applehelp_icon), + path.join(resources_dir, info_plist['HPDBookIconPath'])) + + self.info('done') + except Exception as err: + self.warn('cannot copy icon file %r: %s' % + (path.join(self.srcdir, self.config.applehelp_icon), + err)) + del info_plist['HPDBookIconPath'] + + # Build the access page + self.info(bold('building access page...'), nonl=True) + f = codecs.open(path.join(language_dir, '_access.html'), 'w') + try: + f.write(access_page_template % { + 'toc': htmlescape(toc, quote=True), + 'title': htmlescape(self.config.applehelp_title) + }) + finally: + f.close() + self.info('done') + + # Generate the help index + self.info(bold('generating help index... '), nonl=True) + + args = [ + self.config.applehelp_indexer_path, + '-Cf', + path.join(language_dir, 'search.helpindex'), + language_dir + ] + + if self.config.applehelp_index_anchors is not None: + args.append('-a') + + if self.config.applehelp_min_term_length is not None: + args += ['-m', '%s' % self.config.applehelp_min_term_length] + + if self.config.applehelp_stopwords is not None: + args += ['-s', self.config.applehelp_stopwords] + + if self.config.applehelp_locale is not None: + args += ['-l', self.config.applehelp_locale] + + if self.config.applehelp_disable_external_tools: + self.info('skipping') + + self.warn('you will need to index this help book with:\n %s' + % (' '.join([pipes.quote(arg) for arg in args]))) + else: + p = subprocess.Popen(args, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + output = p.communicate()[0] + + if p.returncode != 0: + raise AppleHelpIndexerFailed(output) + else: + self.info('done') + + # If we've been asked to, sign the bundle + if self.config.applehelp_codesign_identity: + self.info(bold('signing help book... '), nonl=True) + + args = [ + self.config.applehelp_codesign_path, + '-s', self.config.applehelp_codesign_identity, + '-f' + ] + + args += self.config.applehelp_codesign_flags + + args.append(self.bundle_path) + + if self.config.applehelp_disable_external_tools: + self.info('skipping') + + self.warn('you will need to sign this help book with:\n %s' + % (' '.join([pipes.quote(arg) for arg in args]))) + else: + p = subprocess.Popen(args, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + output = p.communicate()[0] + + if p.returncode != 0: + raise AppleHelpCodeSigningFailed(output) + else: + self.info('done') + diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index d53eded6d..2880f58b2 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -78,7 +78,8 @@ class StandaloneHTMLBuilder(Builder): searchindex_filename = 'searchindex.js' add_permalinks = True embedded = False # for things like HTML help or Qt help: suppresses sidebar - + search = True # for things like HTML help and Apple help: suppress search + # This is a class attribute because it is mutated by Sphinx.add_javascript. script_files = ['_static/jquery.js', '_static/underscore.js', '_static/doctools.js'] @@ -247,14 +248,16 @@ class StandaloneHTMLBuilder(Builder): def prepare_writing(self, docnames): # create the search indexer - from sphinx.search import IndexBuilder, languages - lang = self.config.html_search_language or self.config.language - if not lang or lang not in languages: - lang = 'en' - self.indexer = IndexBuilder(self.env, lang, - self.config.html_search_options, - self.config.html_search_scorer) - self.load_indexer(docnames) + self.indexer = None + if self.search: + from sphinx.search import IndexBuilder, languages + lang = self.config.html_search_language or self.config.language + if not lang or lang not in languages: + lang = 'en' + self.indexer = IndexBuilder(self.env, lang, + self.config.html_search_options, + self.config.html_search_scorer) + self.load_indexer(docnames) self.docwriter = HTMLWriter(self) self.docsettings = OptionParser( @@ -485,12 +488,12 @@ class StandaloneHTMLBuilder(Builder): self.handle_page(pagename, {}, template) # the search page - if self.name != 'htmlhelp': + if self.search: self.info(' search', nonl=1) self.handle_page('search', {}, 'search.html') # the opensearch xml file - if self.config.html_use_opensearch and self.name != 'htmlhelp': + if self.config.html_use_opensearch and self.search: self.info(' opensearch', nonl=1) fn = path.join(self.outdir, '_static', 'opensearch.xml') self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn) @@ -580,9 +583,11 @@ class StandaloneHTMLBuilder(Builder): copyfile(jsfile, path.join(self.outdir, '_static', 'translations.js')) - # add context items for search function used in searchtools.js_t ctx = self.globalcontext.copy() - ctx.update(self.indexer.context_for_searchtool()) + + # add context items for search function used in searchtools.js_t + if self.indexer is not None: + ctx.update(self.indexer.context_for_searchtool()) # then, copy over theme-supplied static files if self.theme: @@ -804,7 +809,8 @@ class StandaloneHTMLBuilder(Builder): copyfile(self.env.doc2path(pagename), source_name) def handle_finish(self): - self.finish_tasks.add_task(self.dump_search_index) + if self.indexer: + self.finish_tasks.add_task(self.dump_search_index) self.finish_tasks.add_task(self.dump_inventory) def dump_inventory(self): diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py index c93f8c6c8..8085ee145 100644 --- a/sphinx/builders/htmlhelp.py +++ b/sphinx/builders/htmlhelp.py @@ -173,6 +173,9 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder): # don't add sidebar etc. embedded = True + # don't generate search index or include search page + search = False + lcid = 0x409 encoding = 'cp1252' diff --git a/sphinx/config.py b/sphinx/config.py index 99376247c..de77401f9 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -10,9 +10,11 @@ """ import re -from os import path +from os import path, environ +import shlex from six import PY3, iteritems, string_types, binary_type, integer_types +from six.moves.urllib.parse import quote as urlquote from sphinx.errors import ConfigError from sphinx.locale import l_ @@ -131,6 +133,35 @@ class Config(object): # Devhelp only options devhelp_basename = (lambda self: make_filename(self.project), None), + # Apple help options + applehelp_bundle_name = (lambda self: make_filename(self.project), + 'applehelp'), + applehelp_bundle_id = (None, 'applehelp'), + applehelp_dev_region = ('en-us', 'applehelp'), + applehelp_bundle_version = ('1', 'applehelp'), + applehelp_icon = (None, 'applehelp'), + applehelp_kb_product = (lambda self: '%s-%s' \ + % (make_filename(self.project), self.release), + 'applehelp'), + applehelp_kb_url = (None, 'applehelp'), + applehelp_remote_url = (None, 'applehelp'), + applehelp_index_anchors = (False, 'applehelp'), + applehelp_min_term_length = (None, 'applehelp'), + applehelp_stopwords = (lambda self: self.language or 'en', 'applehelp'), + applehelp_locale = (lambda self: self.language or 'en', 'applehelp'), + applehelp_title = (lambda self: self.project + ' Help', 'applehelp'), + applehelp_codesign_identity = (lambda self: + environ.get('CODE_SIGN_IDENTITY', None), + 'applehelp'), + applehelp_codesign_flags = (lambda self: + shlex.split( + environ.get('OTHER_CODE_SIGN_FLAGS', + '')), + 'applehelp'), + applehelp_indexer_path = ('/usr/bin/hiutil', 'applehelp'), + applehelp_codesign_path = ('/usr/bin/codesign', 'applehelp'), + applehelp_disable_external_tools = (False, None), + # Epub options epub_basename = (lambda self: make_filename(self.project), None), epub_theme = ('epub', 'html'), diff --git a/sphinx/environment.py b/sphinx/environment.py index 9ea57410b..661513041 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -460,7 +460,7 @@ class BuildEnvironment: config.exclude_patterns[:] + config.templates_path + config.html_extra_path + - ['**/_sources', '.#*'] + ['**/_sources', '.#*', '*.lproj/**'] ) self.found_docs = set(get_matching_docs( self.srcdir, config.source_suffix, exclude_matchers=matchers)) diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index ed714d939..8f4e0ed52 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -32,6 +32,7 @@ except ImportError: from six import PY2, PY3, text_type from six.moves import input +from six.moves.urllib.parse import quote as urlquote from docutils.utils import column_width from sphinx import __version__ @@ -86,6 +87,7 @@ QUICKSTART_CONF += u'''\ import sys import os +import shlex # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -496,6 +498,7 @@ help: \t@echo " json to make JSON files" \t@echo " htmlhelp to make HTML files and a HTML help project" \t@echo " qthelp to make HTML files and a qthelp project" +\t@echo " applehelp to make an Apple Help Book" \t@echo " devhelp to make HTML files and a Devhelp project" \t@echo " epub to make an epub" \t@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @@ -557,6 +560,14 @@ qthelp: \t@echo "To view the help file:" \t@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/%(project_fn)s.qhc" +applehelp: +\t$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp +\t@echo +\t@echo "Build finished. The help book is in $(BUILDDIR)/applehelp." +\t@echo "N.B. You won't be able to view it unless you put it in" \\ +\t "~/Library/Documentation/Help or install it in your application" \\ +\t "bundle." + devhelp: \t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp \t@echo @@ -1278,6 +1289,7 @@ def generate(d, overwrite=True, silent=False): d['mastertocmaxdepth'] = 2 d['project_fn'] = make_filename(d['project']) + d['project_url'] = urlquote(d['project'].encode('idna')) d['project_manpage'] = d['project_fn'].lower() d['now'] = time.asctime() d['project_underline'] = column_width(d['project']) * '=' diff --git a/tests/root/conf.py b/tests/root/conf.py index e8dd36138..bdf2f8c8d 100644 --- a/tests/root/conf.py +++ b/tests/root/conf.py @@ -43,6 +43,9 @@ html_context = {'hckey': 'hcval', 'hckey_co': 'wrong_hcval_co'} htmlhelp_basename = 'SphinxTestsdoc' +applehelp_bundle_id = 'org.sphinx-doc.Sphinx.help' +applehelp_disable_external_tools = True + latex_documents = [ ('contents', 'SphinxTests.tex', 'Sphinx Tests Documentation', 'Georg Brandl \\and someone else', 'manual'), diff --git a/tests/root/en.lproj/localized.txt b/tests/root/en.lproj/localized.txt new file mode 100644 index 000000000..20e1b2b05 --- /dev/null +++ b/tests/root/en.lproj/localized.txt @@ -0,0 +1,2 @@ +This file should be included in the final bundle by the applehelp builder. +It should be ignored by other builders. diff --git a/tests/test_build.py b/tests/test_build.py index 5aec0d3d8..ed39f6971 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -66,9 +66,10 @@ def test_build_all(): ).encode('utf-8')) # note: no 'html' - if it's ok with dirhtml it's ok with html - for buildername in ['dirhtml', 'singlehtml', 'latex', 'texinfo', - 'pickle', 'json', 'text', 'htmlhelp', 'qthelp', 'epub', - 'changes', 'xml', 'pseudoxml', 'man', 'linkcheck']: + for buildername in ['dirhtml', 'singlehtml', 'latex', 'texinfo', 'pickle', + 'json', 'text', 'htmlhelp', 'qthelp', 'epub', + 'applehelp', 'changes', 'xml', 'pseudoxml', 'man', + 'linkcheck']: yield verify_build, buildername, srcdir diff --git a/tests/test_build_applehelp.py b/tests/test_build_applehelp.py new file mode 100644 index 000000000..8d778f78f --- /dev/null +++ b/tests/test_build_applehelp.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +""" + test_build_applehelp + ~~~~~~~~~~~~~~~~~~~~ + + Test the Apple Help builder and check its output. We don't need to + test the HTML itself; that's already handled by + :file:`test_build_html.py`. + + :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import os +import plistlib + +from util import with_app +from path import path + +# Use plistlib.load in 3.4 and above +try: + read_plist = plistlib.load +except AttributeError: + read_plist = plistlib.readPlist + + +def check_structure(outdir): + contentsdir = outdir / 'Contents' + assert contentsdir.isdir() + assert (contentsdir / 'Info.plist').isfile() + + with open(contentsdir / 'Info.plist', 'rb') as f: + plist = read_plist(f) + assert plist + assert len(plist) + assert plist.get('CFBundleIdentifier', None) == 'org.sphinx-doc.Sphinx.help' + + assert (contentsdir / 'Resources').isdir() + assert (contentsdir / 'Resources' / 'en.lproj').isdir() + + +def check_localization(outdir): + lprojdir = outdir / 'Contents' / 'Resources' / 'en.lproj' + assert (lprojdir / 'localized.txt').isfile() + + +@with_app(buildername='applehelp') +def test_applehelp_output(app, status, warning): + app.builder.build_all() + + # Have to use bundle_path, not outdir, because we alter the latter + # to point to the lproj directory so that the HTML arrives in the + # correct location. + bundle_path = path(app.builder.bundle_path) + check_structure(bundle_path) + check_localization(bundle_path) |