diff --git a/sphinx/builders/applehelp.py b/sphinx/builders/applehelp.py index e87d47fda..43969a7eb 100644 --- a/sphinx/builders/applehelp.py +++ b/sphinx/builders/applehelp.py @@ -8,21 +8,21 @@ :license: BSD, see LICENSE for details. """ -import html -import pipes import plistlib import shlex import subprocess from os import path, environ +from subprocess import CalledProcessError, PIPE, STDOUT +from sphinx import package_dir from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.errors import SphinxError from sphinx.locale import __ from sphinx.util import logging from sphinx.util.console import bold # type: ignore -from sphinx.util.fileutil import copy_asset +from sphinx.util.fileutil import copy_asset, copy_asset_file from sphinx.util.matching import Matcher -from sphinx.util.osutil import copyfile, ensuredir, make_filename +from sphinx.util.osutil import ensuredir, make_filename if False: # For type annotation @@ -31,22 +31,7 @@ if False: logger = logging.getLogger(__name__) - -# False access page (used because helpd expects strict XHTML) -access_page_template = '''\ - - - - %(title)s - - - - - - - -''' +template_dir = path.join(package_dir, 'templates', 'applehelp') class AppleHelpIndexerFailed(SphinxError): @@ -128,13 +113,17 @@ class AppleHelpBuilder(StandaloneHTMLBuilder): resources_dir = path.join(contents_dir, 'Resources') language_dir = path.join(resources_dir, self.config.applehelp_locale + '.lproj') + ensuredir(language_dir) - for d in [contents_dir, resources_dir, language_dir]: - ensuredir(d) - - # Construct the Info.plist file - toc = self.config.master_doc + self.out_suffix + self.build_info_plist(contents_dir) + self.copy_applehelp_icon(resources_dir) + self.build_access_page(language_dir) + self.build_helpindex(language_dir) + self.do_codesign() + def build_info_plist(self, contents_dir): + # type: (str) -> None + """Construct the Info.plist file.""" info_plist = { 'CFBundleDevelopmentRegion': self.config.applehelp_dev_region, 'CFBundleIdentifier': self.config.applehelp_bundle_id, @@ -151,8 +140,7 @@ class AppleHelpBuilder(StandaloneHTMLBuilder): } if self.config.applehelp_icon is not None: - info_plist['HPDBookIconPath'] \ - = path.basename(self.config.applehelp_icon) + 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 @@ -162,34 +150,37 @@ class AppleHelpBuilder(StandaloneHTMLBuilder): info_plist['HPDBookRemoteURL'] = self.config.applehelp_remote_url logger.info(bold(__('writing Info.plist... ')), nonl=True) - with open(path.join(contents_dir, 'Info.plist'), 'wb') as fb: - plistlib.dump(info_plist, fb) + with open(path.join(contents_dir, 'Info.plist'), 'wb') as f: + plistlib.dump(info_plist, f) logger.info(__('done')) - # Copy the icon, if one is supplied + def copy_applehelp_icon(self, resources_dir): + # type: (str) -> None + """Copy the icon, if one is supplied.""" if self.config.applehelp_icon: logger.info(bold(__('copying icon... ')), nonl=True) try: - copyfile(path.join(self.srcdir, self.config.applehelp_icon), - path.join(resources_dir, info_plist['HPDBookIconPath'])) - + applehelp_icon = path.join(self.srcdir, self.config.applehelp_icon) + copy_asset_file(applehelp_icon, resources_dir) logger.info(__('done')) except Exception as err: - logger.warning(__('cannot copy icon file %r: %s'), - path.join(self.srcdir, self.config.applehelp_icon), err) - del info_plist['HPDBookIconPath'] + logger.warning(__('cannot copy icon file %r: %s'), applehelp_icon, err) - # Build the access page + def build_access_page(self, language_dir): + # type: (str) -> None + """Build the access page.""" logger.info(bold(__('building access page...')), nonl=True) - with open(path.join(language_dir, '_access.html'), 'w') as ft: - ft.write(access_page_template % { - 'toc': html.escape(toc, quote=True), - 'title': html.escape(self.config.applehelp_title) - }) + context = { + 'toc': self.config.master_doc + self.out_suffix, + 'title': self.config.applehelp_title, + } + copy_asset_file(path.join(template_dir, '_access.html_t'), language_dir, context) logger.info(__('done')) - # Generate the help index + def build_helpindex(self, language_dir): + # type: (str) -> None + """Generate the help index.""" logger.info(bold(__('generating help index... ')), nonl=True) args = [ @@ -213,25 +204,20 @@ class AppleHelpBuilder(StandaloneHTMLBuilder): if self.config.applehelp_disable_external_tools: logger.info(__('skipping')) - logger.warning(__('you will need to index this help book with:\n %s'), - ' '.join([pipes.quote(arg) for arg in args])) + ' '.join([shlex.quote(arg) for arg in args])) else: try: - p = subprocess.Popen(args, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - - output = p.communicate()[0] - - if p.returncode != 0: - raise AppleHelpIndexerFailed(output) - else: - logger.info(__('done')) + subprocess.run(args, stdout=PIPE, stderr=STDOUT, check=True) + logger.info(__('done')) except OSError: raise AppleHelpIndexerFailed(__('Command not found: %s') % args[0]) + except CalledProcessError as exc: + raise AppleHelpCodeSigningFailed(exc.stdout) - # If we've been asked to, sign the bundle + def do_codesign(self): + # type: () -> None + """If we've been asked to, sign the bundle.""" if self.config.applehelp_codesign_identity: logger.info(bold(__('signing help book... ')), nonl=True) @@ -248,21 +234,15 @@ class AppleHelpBuilder(StandaloneHTMLBuilder): if self.config.applehelp_disable_external_tools: logger.info(__('skipping')) logger.warning(__('you will need to sign this help book with:\n %s'), - ' '.join([pipes.quote(arg) for arg in args])) + ' '.join([shlex.quote(arg) for arg in args])) else: try: - p = subprocess.Popen(args, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - - output = p.communicate()[0] - - if p.returncode != 0: - raise AppleHelpCodeSigningFailed(output) - else: - logger.info(__('done')) + subprocess.run(args, stdout=PIPE, stderr=STDOUT, check=True) + logger.info(__('done')) except OSError: raise AppleHelpCodeSigningFailed(__('Command not found: %s') % args[0]) + except CalledProcessError as exc: + raise AppleHelpCodeSigningFailed(exc.stdout) def setup(app): diff --git a/sphinx/templates/applehelp/_access.html_t b/sphinx/templates/applehelp/_access.html_t new file mode 100644 index 000000000..aa6b2dcc4 --- /dev/null +++ b/sphinx/templates/applehelp/_access.html_t @@ -0,0 +1,12 @@ + + + + {{ title|e }} + + + + + + +