def write_toc(self, node, indentlevel=4): # XXX this should return a Unicode string, not a bytestring parts = [] if self.isdocnode(node): refnode = node.children[0][0] link = refnode["refuri"] title = htmlescape(refnode.astext()).replace('"', """) item = '<section title="%(title)s" ref="%(ref)s">' % {"title": title, "ref": link} parts.append(" " * 4 * indentlevel + item) for subnode in node.children[1]: parts.extend(self.write_toc(subnode, indentlevel + 1)) parts.append(" " * 4 * indentlevel + "</section>") elif isinstance(node, nodes.list_item): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) elif isinstance(node, nodes.reference): link = node["refuri"] title = htmlescape(node.astext()).replace('"', """) item = section_template % {"title": title, "ref": link} item = u" " * 4 * indentlevel + item parts.append(item.encode("ascii", "xmlcharrefreplace")) elif isinstance(node, nodes.bullet_list): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) elif isinstance(node, addnodes.compact_paragraph): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) return parts
def write_toc(self, node, indentlevel=4): # XXX this should return a Unicode string, not a bytestring parts = [] if self.isdocnode(node): refnode = node.children[0][0] link = refnode['refuri'] title = htmlescape(refnode.astext()).replace('"', '"') item = '<section title="%(title)s" ref="%(ref)s">' % \ {'title': title, 'ref': link} parts.append(' '*4*indentlevel + item) for subnode in node.children[1]: parts.extend(self.write_toc(subnode, indentlevel+1)) parts.append(' '*4*indentlevel + '</section>') elif isinstance(node, nodes.list_item): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) elif isinstance(node, nodes.reference): link = node['refuri'] title = htmlescape(node.astext()).replace('"','"') item = section_template % {'title': title, 'ref': link} item = u' ' * 4 * indentlevel + item parts.append(item.encode('ascii', 'xmlcharrefreplace')) elif isinstance(node, nodes.bullet_list): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) elif isinstance(node, addnodes.compact_paragraph): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) return parts
def write_toc(self, node, indentlevel=4): # type: (nodes.Node, int) -> List[unicode] # XXX this should return a Unicode string, not a bytestring parts = [] # type: List[unicode] if self.isdocnode(node): refnode = node.children[0][0] link = refnode['refuri'] title = htmlescape(refnode.astext()).replace('"', '"') item = '<section title="%(title)s" ref="%(ref)s">' % \ {'title': title, 'ref': link} parts.append(' ' * 4 * indentlevel + item) for subnode in node.children[1]: parts.extend(self.write_toc(subnode, indentlevel + 1)) parts.append(' ' * 4 * indentlevel + '</section>') elif isinstance(node, nodes.list_item): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) elif isinstance(node, nodes.reference): link = node['refuri'] title = htmlescape(node.astext()).replace('"', '"') item = section_template % {'title': title, 'ref': link} item = u' ' * 4 * indentlevel + item parts.append(item.encode('ascii', 'xmlcharrefreplace')) elif isinstance(node, nodes.bullet_list): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) elif isinstance(node, addnodes.compact_paragraph): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) return parts
def write_toc(self, node, indentlevel=4): # type: (nodes.Node, int) -> List[unicode] parts = [] # type: List[unicode] if isinstance(node, nodes.list_item) and self.isdocnode(node): compact_paragraph = cast(addnodes.compact_paragraph, node[0]) reference = cast(nodes.reference, compact_paragraph[0]) link = reference['refuri'] title = htmlescape(reference.astext()).replace('"', '"') item = '<section title="%(title)s" ref="%(ref)s">' % \ {'title': title, 'ref': link} parts.append(' ' * 4 * indentlevel + item) bullet_list = cast(nodes.bullet_list, node[1]) list_items = cast(Iterable[nodes.list_item], bullet_list) for list_item in list_items: parts.extend(self.write_toc(list_item, indentlevel + 1)) parts.append(' ' * 4 * indentlevel + '</section>') elif isinstance(node, nodes.list_item): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) elif isinstance(node, nodes.reference): link = node['refuri'] title = htmlescape(node.astext()).replace('"', '"') item = section_template % {'title': title, 'ref': link} item = u' ' * 4 * indentlevel + item parts.append(item.encode('ascii', 'xmlcharrefreplace').decode()) elif isinstance(node, nodes.bullet_list): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) elif isinstance(node, addnodes.compact_paragraph): for subnode in node: parts.extend(self.write_toc(subnode, indentlevel)) return parts
def page_link(path, name): uri = app.builder.get_relative_uri(pagename, path) return ( '<a href="%s" class="reference internal%s">%s</a>' ) % ( htmlescape(uri), ' current' if pagename == path else '', htmlescape(name), )
def _parse_comment_text(self, text): settings = {"file_insertion_enabled": False, "raw_enabled": False, "output_encoding": "unicode"} try: ret = publish_parts(text, writer_name="html", settings_overrides=settings)["fragment"] except Exception: ret = htmlescape(text) return ret
def hl(no, line): line = '<a name="L%s"> </a>' % no + htmlescape(line) for x in hltext: if x in line: line = '<span class="hl">%s</span>' % line break return line
def get_objects(self, fn2index): rv = {} otypes = self._objtypes onames = self._objnames for domainname, domain in sorted(iteritems(self.env.domains)): for fullname, dispname, type, docname, anchor, prio in \ sorted(domain.get_objects()): # XXX use dispname? if docname not in fn2index: continue if prio < 0: continue fullname = htmlescape(fullname) prefix, name = rpartition(fullname, '.') pdict = rv.setdefault(prefix, {}) try: typeindex = otypes[domainname, type] except KeyError: typeindex = len(otypes) otypes[domainname, type] = typeindex otype = domain.object_types.get(type) if otype: # use unicode() to fire translation proxies onames[typeindex] = (domainname, type, text_type(domain.get_type_name(otype))) else: onames[typeindex] = (domainname, type, type) if anchor == fullname: shortanchor = '' elif anchor == type + '-' + fullname: shortanchor = '-' else: shortanchor = anchor pdict[name] = (fn2index[docname], typeindex, prio, shortanchor) return rv
def write_index(title, refs, subitems): # type: (unicode, List[Tuple[unicode, unicode]], List[Tuple[unicode, List[Tuple[unicode, unicode]]]]) -> None # NOQA def write_param(name, value): # type: (unicode, unicode) -> None item = ' <param name="%s" value="%s">\n' % \ (name, value) f.write(item) title = htmlescape(title) f.write('<LI> <OBJECT type="text/sitemap">\n') write_param('Keyword', title) if len(refs) == 0: write_param('See Also', title) elif len(refs) == 1: write_param('Local', refs[0][1]) else: for i, ref in enumerate(refs): # XXX: better title? write_param('Name', '[%d] %s' % (i, ref[1])) write_param('Local', ref[1]) f.write('</OBJECT>\n') if subitems: f.write('<UL> ') for subitem in subitems: write_index(subitem[0], subitem[1], []) f.write('</UL>')
def hl(self, text, version): # type: (unicode, unicode) -> unicode text = htmlescape(text) for directive in ['versionchanged', 'versionadded', 'deprecated']: text = text.replace('.. %s:: %s' % (directive, version), '<b>.. %s:: %s</b>' % (directive, version)) return text
def _parse_comment_text(self, text): settings = {'file_insertion_enabled': False, 'raw_enabled': False, 'output_encoding': 'unicode'} try: ret = publish_parts(text, writer_name='html', settings_overrides=settings)['fragment'] except Exception: ret = htmlescape(text) return ret
def unhighlighted(self, source): if self.dest == 'html': return '<pre>' + htmlescape(source) + '</pre>\n' else: # first, escape highlighting characters like Pygments does source = source.translate(escape_hl_chars) # then, escape all characters nonrepresentable in LaTeX source = source.translate(tex_hl_escape_map_new) return '\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n' + \ source + '\\end{Verbatim}\n'
def new_build_keywords(self, title, refs, subitems): old_items = old_build_keywords(self, title, refs, subitems) new_items = [] for item in old_items: before, rest = item.split("ref=\"", 1) ref, after = rest.split("\"") if ("<" in ref and ">" in ref): new_items.append(before + 'ref="' + htmlescape(ref) + '"' + after) else: new_items.append(item) return new_items
def new_build_keywords(self, title, refs, subitems): old_items = old_build_keywords(self, title, refs, subitems) new_items = [] for item in old_items: before, rest = item.split("ref=\"", 1) ref, after = rest.split("\"") if ("<" in ref and ">" in ref): new_items.append(before + "ref=\"" + htmlescape(ref) + "\"" + after) else: new_items.append(item) return new_items
def new_build_keywords(self, title, refs, subitems): old_items = old_build_keywords(self, title, refs, subitems) new_items = [] for item in old_items: before, rest = item.split('ref="', 1) ref, after = rest.split('"') if "<" in ref and ">" in ref: new_items.append(before + 'ref="' + htmlescape(ref) + '"' + after) else: new_items.append(item) return new_items
def keyword_item(self, name, ref): # type: (unicode, Any) -> unicode matchobj = _idpattern.match(name) # type: ignore if matchobj: groupdict = matchobj.groupdict() shortname = groupdict['title'] id = groupdict.get('id') # descr = groupdict.get('descr') if shortname.endswith('()'): shortname = shortname[:-2] id = '%s.%s' % (id, shortname) else: id = None nameattr = htmlescape(name, quote=True) refattr = htmlescape(ref[1], quote=True) if id: item = ' ' * 12 + '<keyword name="%s" id="%s" ref="%s"/>' % (nameattr, id, refattr) else: item = ' ' * 12 + '<keyword name="%s" ref="%s"/>' % (nameattr, refattr) item.encode('ascii', 'xmlcharrefreplace') return item
def unhighlighted(self, source): # type: (unicode) -> unicode warnings.warn('PygmentsBridge.unhighlighted() is now deprecated.', RemovedInSphinx30Warning) if self.dest == 'html': return '<pre>' + htmlescape(source) + '</pre>\n' else: # first, escape highlighting characters like Pygments does source = source.translate(escape_hl_chars) # then, escape all characters nonrepresentable in LaTeX source = source.translate(tex_hl_escape_map_new) return '\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n' + \ source + '\\end{Verbatim}\n'
def css_tag(css): attrs = [] for key in sorted(css.attributes): value = css.attributes[key] if value is not None: if sphinx.version_info < (2, 0): # https://github.com/sphinx-doc/sphinx/blob/v1.8.5/sphinx/builders/html.py#L1144 from sphinx.util.pycompat import htmlescape attrs.append('%s="%s"' % (key, htmlescape(value, True))) else: import html attrs.append('%s="%s"' % (key, html.escape(value, True))) attrs.append('href="%s"' % pathto(css.filename, resource=True)) return '<link %s />' % ' '.join(attrs)
def chm_htmlescape(s, quote=None): # type: (unicode, bool) -> unicode """ chm_htmlescape() is a wrapper of html.escape(). .hhc/.hhk files don't recognize hex escaping, we need convert hex escaping to decimal escaping. for example: ``'`` -> ``'`` html.escape() may generates a hex escaping ``'`` for single quote ``'``, this wrapper fixes this. """ if quote is None: quote = PY3 # True for py3, False for py2 (for compatibility) s = htmlescape(s, quote) s = s.replace(''', ''') # re-escape as decimal return s
def insert_canonical_link(app, pagename, templatename, context, doctree): # skip unless html builder & redirect configured helper = RedirectHelper(app) root_url = helper.domain_root if not helper.for_html or not root_url: return # XXX: any gotchas w/ generating url from pagename this way? url = "%s/%s.html" % (root_url.rstrip("/"), pagename) # insert "canonical" link to help search engines # XXX: skipping this if another ext sets this? # XXX: split this out under separate name / extension? meta = context.get("metatags", "") context[ 'metatags'] = meta + '<link rel="canonical" href="%s" />\n' % htmlescape( url, True)
def write_toc(node, ullevel=0): if isinstance(node, nodes.list_item): f.write('<LI> ') for subnode in node: write_toc(subnode, ullevel) elif isinstance(node, nodes.reference): link = node['refuri'] title = htmlescape(node.astext()).replace('"', '"') f.write(object_sitemap % (title, link)) elif isinstance(node, nodes.bullet_list): if ullevel != 0: f.write('<UL>\n') for subnode in node: write_toc(subnode, ullevel + 1) if ullevel != 0: f.write('</UL>\n') elif isinstance(node, addnodes.compact_paragraph): for subnode in node: write_toc(subnode, ullevel)
def write_toc(node, ullevel=0): if isinstance(node, nodes.list_item): f.write('<LI> ') for subnode in node: write_toc(subnode, ullevel) elif isinstance(node, nodes.reference): link = node['refuri'] title = htmlescape(node.astext()).replace('"', '"') f.write(object_sitemap % (title, link)) elif isinstance(node, nodes.bullet_list): if ullevel != 0: f.write('<UL>\n') for subnode in node: write_toc(subnode, ullevel+1) if ullevel != 0: f.write('</UL>\n') elif isinstance(node, addnodes.compact_paragraph): for subnode in node: write_toc(subnode, ullevel)
def build_keywords(self, title, refs, subitems): keywords = [] title = htmlescape(title) # if len(refs) == 0: # XXX # write_param('See Also', title) if len(refs) == 1: keywords.append(self.keyword_item(title, refs[0])) elif len(refs) > 1: for i, ref in enumerate(refs): # XXX # item = (' '*12 + # '<keyword name="%s [%d]" ref="%s"/>' % ( # title, i, ref)) # item.encode('ascii', 'xmlcharrefreplace') # keywords.append(item) keywords.append(self.keyword_item(title, ref)) if subitems: for subitem in subitems: keywords.extend(self.build_keywords(subitem[0], subitem[1], [])) return keywords
def write_index(title, refs, subitems): def write_param(name, value): item = ' <param name="%s" value="%s">\n' % (name, value) f.write(item) title = htmlescape(title) f.write('<LI> <OBJECT type="text/sitemap">\n') write_param("Keyword", title) if len(refs) == 0: write_param("See Also", title) elif len(refs) == 1: write_param("Local", refs[0][1]) else: for i, ref in enumerate(refs): # XXX: better title? write_param("Name", "[%d] %s" % (i, ref[1])) write_param("Local", ref[1]) f.write("</OBJECT>\n") if subitems: f.write("<UL> ") for subitem in subitems: write_index(subitem[0], subitem[1], []) f.write("</UL>")
def get_objects(self): for kv in self.data['objects'].items(): (fullid, (docname, objtype, fullname, shortname, specname, displaytype)) = kv yield (htmlescape(fullname), specname, objtype, docname, fullid, 0)
def hl(self, text, version): text = htmlescape(text) for directive in ["versionchanged", "versionadded", "deprecated"]: text = text.replace(".. %s:: %s" % (directive, version), "<b>.. %s:: %s</b>" % (directive, version)) return text
def __init__(self, source, proposal): proposal = htmlescape(proposal) differ = Differ() self.diff = list( differ.compare(source.splitlines(1), proposal.splitlines(1)))
def __init__(self, source, proposal): proposal = htmlescape(proposal) differ = Differ() self.diff = list(differ.compare(source.splitlines(1), proposal.splitlines(1)))
def build_helpbook(self): # type: () -> None 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 logger.info(bold('writing Info.plist... '), nonl=True) with open(path.join(contents_dir, 'Info.plist'), 'wb') as f: write_plist(info_plist, f) logger.info('done') # 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'])) 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'] # Build the access page logger.info(bold('building access page...'), nonl=True) with codecs.open(path.join(language_dir, '_access.html'), 'w') as f: f.write( access_page_template % { 'toc': htmlescape(toc, quote=True), 'title': htmlescape(self.config.applehelp_title) }) logger.info('done') # Generate the help index logger.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: logger.info('skipping') logger.warning('you will need to index this help book with:\n %s', ' '.join([pipes.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') except OSError: raise AppleHelpIndexerFailed('Command not found: %s' % args[0]) # If we've been asked to, sign the bundle if self.config.applehelp_codesign_identity: logger.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: logger.info('skipping') logger.warning( 'you will need to sign this help book with:\n %s', ' '.join([pipes.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') except OSError: raise AppleHelpCodeSigningFailed('Command not found: %s' % args[0])
def build_qhp(self, outdir, outname): self.info("writing project file...") # sections tocdoc = self.env.get_and_resolve_doctree(self.config.master_doc, self, prune_toctrees=False) def istoctree(node): return isinstance(node, addnodes.compact_paragraph) and "toctree" in node sections = [] for node in tocdoc.traverse(istoctree): sections.extend(self.write_toc(node)) for indexname, indexcls, content, collapse in self.domain_indices: item = section_template % {"title": indexcls.localname, "ref": "%s.html" % indexname} sections.append(" " * 4 * 4 + item) # sections may be unicode strings or byte strings, we have to make sure # they are all unicode strings before joining them new_sections = [] for section in sections: if not isinstance(section, text_type): new_sections.append(force_decode(section, None)) else: new_sections.append(section) sections = u"\n".join(new_sections) # keywords keywords = [] index = self.env.create_index(self, group_entries=False) for (key, group) in index: for title, (refs, subitems, key_) in group: keywords.extend(self.build_keywords(title, refs, subitems)) keywords = u"\n".join(keywords) # files if not outdir.endswith(os.sep): outdir += os.sep olen = len(outdir) projectfiles = [] staticdir = path.join(outdir, "_static") imagesdir = path.join(outdir, self.imagedir) for root, dirs, files in os.walk(outdir): resourcedir = root.startswith(staticdir) or root.startswith(imagesdir) for fn in files: if (resourcedir and not fn.endswith(".js")) or fn.endswith(".html"): filename = path.join(root, fn)[olen:] projectfiles.append(file_template % {"filename": htmlescape(filename)}) projectfiles = "\n".join(projectfiles) # it seems that the "namespace" may not contain non-alphanumeric # characters, and more than one successive dot, or leading/trailing # dots, are also forbidden nspace = "org.sphinx.%s.%s" % (outname, self.config.version) nspace = re.sub("[^a-zA-Z0-9.]", "", nspace) nspace = re.sub(r"\.+", ".", nspace).strip(".") nspace = nspace.lower() # write the project file with codecs.open(path.join(outdir, outname + ".qhp"), "w", "utf-8") as f: f.write( project_template % { "outname": htmlescape(outname), "title": htmlescape(self.config.html_title), "version": htmlescape(self.config.version), "project": htmlescape(self.config.project), "namespace": htmlescape(nspace), "masterdoc": htmlescape(self.config.master_doc), "sections": sections, "keywords": keywords, "files": projectfiles, } ) homepage = "qthelp://" + posixpath.join(nspace, "doc", self.get_target_uri(self.config.master_doc)) startpage = "qthelp://" + posixpath.join(nspace, "doc", "index.html") self.info("writing collection project file...") with codecs.open(path.join(outdir, outname + ".qhcp"), "w", "utf-8") as f: f.write( collection_template % { "outname": htmlescape(outname), "title": htmlescape(self.config.html_short_title), "homepage": htmlescape(homepage), "startpage": htmlescape(startpage), } )
def build_qhp(self, outdir, outname): self.info('writing project file...') # sections tocdoc = self.env.get_and_resolve_doctree(self.config.master_doc, self, prune_toctrees=False) istoctree = lambda node: ( isinstance(node, addnodes.compact_paragraph) and 'toctree' in node) sections = [] for node in tocdoc.traverse(istoctree): sections.extend(self.write_toc(node)) for indexname, indexcls, content, collapse in self.domain_indices: item = section_template % {'title': indexcls.localname, 'ref': '%s.html' % indexname} sections.append(' ' * 4 * 4 + item) # sections may be unicode strings or byte strings, we have to make sure # they are all unicode strings before joining them new_sections = [] for section in sections: if not isinstance(section, text_type): new_sections.append(force_decode(section, None)) else: new_sections.append(section) sections = u'\n'.join(new_sections) # keywords keywords = [] index = self.env.create_index(self, group_entries=False) for (key, group) in index: for title, (refs, subitems) in group: keywords.extend(self.build_keywords(title, refs, subitems)) keywords = u'\n'.join(keywords) # files if not outdir.endswith(os.sep): outdir += os.sep olen = len(outdir) projectfiles = [] staticdir = path.join(outdir, '_static') imagesdir = path.join(outdir, self.imagedir) for root, dirs, files in os.walk(outdir): resourcedir = root.startswith(staticdir) or \ root.startswith(imagesdir) for fn in files: if (resourcedir and not fn.endswith('.js')) or \ fn.endswith('.html'): filename = path.join(root, fn)[olen:] projectfiles.append(file_template % {'filename': htmlescape(filename)}) projectfiles = '\n'.join(projectfiles) # it seems that the "namespace" may not contain non-alphanumeric # characters, and more than one successive dot, or leading/trailing # dots, are also forbidden nspace = 'org.sphinx.%s.%s' % (outname, self.config.version) nspace = re.sub('[^a-zA-Z0-9.]', '', nspace) nspace = re.sub(r'\.+', '.', nspace).strip('.') nspace = nspace.lower() # write the project file f = codecs.open(path.join(outdir, outname+'.qhp'), 'w', 'utf-8') try: f.write(project_template % { 'outname': htmlescape(outname), 'title': htmlescape(self.config.html_title), 'version': htmlescape(self.config.version), 'project': htmlescape(self.config.project), 'namespace': htmlescape(nspace), 'masterdoc': htmlescape(self.config.master_doc), 'sections': sections, 'keywords': keywords, 'files': projectfiles}) finally: f.close() homepage = 'qthelp://' + posixpath.join( nspace, 'doc', self.get_target_uri(self.config.master_doc)) startpage = 'qthelp://' + posixpath.join(nspace, 'doc', 'index.html') self.info('writing collection project file...') f = codecs.open(path.join(outdir, outname+'.qhcp'), 'w', 'utf-8') try: f.write(collection_template % { 'outname': htmlescape(outname), 'title': htmlescape(self.config.html_short_title), 'homepage': htmlescape(homepage), 'startpage': htmlescape(startpage)}) finally: f.close()
def build_helpbook(self): # type: () -> None 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 logger.info(bold('writing Info.plist... '), nonl=True) with open(path.join(contents_dir, 'Info.plist'), 'wb') as f: write_plist(info_plist, f) logger.info('done') # 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'])) 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'] # Build the access page logger.info(bold('building access page...'), nonl=True) with codecs.open(path.join(language_dir, '_access.html'), 'w') as f: f.write(access_page_template % { 'toc': htmlescape(toc, quote=True), 'title': htmlescape(self.config.applehelp_title) }) logger.info('done') # Generate the help index logger.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: logger.info('skipping') logger.warning('you will need to index this help book with:\n %s', ' '.join([pipes.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') except OSError: raise AppleHelpIndexerFailed('Command not found: %s' % args[0]) # If we've been asked to, sign the bundle if self.config.applehelp_codesign_identity: logger.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: logger.info('skipping') logger.warning('you will need to sign this help book with:\n %s', ' '.join([pipes.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') except OSError: raise AppleHelpCodeSigningFailed('Command not found: %s' % args[0])