def visit_kernel_render(self, node): """Visitor of the ``kernel_render`` Node. If rendering tools available, save the markup of the ``literal_block`` child node into a file and replace the ``literal_block`` node with a new created ``image`` node, pointing to the saved markup file. Afterwards, handle the image child-node with the ``convert_image(...)``. """ app = self.builder.app srclang = node.get('srclang') kernellog.verbose(app, 'visit kernel-render node lang: "%s"' % (srclang)) tmp_ext = RENDER_MARKUP_EXT.get(srclang, None) if tmp_ext is None: kernellog.warn( app, 'kernel-render: "%s" unknown / include raw.' % (srclang)) return if not dot_cmd and tmp_ext == '.dot': kernellog.verbose(app, "dot from graphviz not available / include raw.") return literal_block = node[0] code = literal_block.astext() hashobj = code.encode('utf-8') # str(node.attributes) fname = path.join('%s-%s' % (srclang, sha1(hashobj).hexdigest())) tmp_fname = path.join(self.builder.outdir, self.builder.imagedir, fname + tmp_ext) if not path.isfile(tmp_fname): mkdir(path.dirname(tmp_fname)) with open(tmp_fname, "w") as out: out.write(code) img_node = nodes.image(node.rawsource, **node.attributes) img_node['uri'] = path.join(self.builder.imgpath, fname + tmp_ext) img_node['candidates'] = { '*': path.join(self.builder.imgpath, fname + tmp_ext) } literal_block.replace_self(img_node) convert_image(img_node, self, tmp_fname)
def svg2pdf(app, svg_fname, pdf_fname): """Converts SVG to PDF with ``inkscape(1)`` or ``convert(1)`` command. Uses ``inkscape(1)`` from Inkscape (https://inkscape.org/) or ``convert(1)`` from ImageMagick (https://www.imagemagick.org) for conversion. Returns ``True`` on success and ``False`` if an error occurred. * ``svg_fname`` pathname of the input SVG file with extension (``.svg``) * ``pdf_name`` pathname of the output PDF file with extension (``.pdf``) """ cmd = [convert_cmd, svg_fname, pdf_fname] cmd_name = 'convert(1)' if inkscape_cmd: cmd_name = 'inkscape(1)' if inkscape_ver_one: cmd = [inkscape_cmd, '-o', pdf_fname, svg_fname] else: cmd = [ inkscape_cmd, '-z', '--export-pdf=%s' % pdf_fname, svg_fname ] try: warning_msg = subprocess.check_output(cmd, stderr=subprocess.STDOUT) exit_code = 0 except subprocess.CalledProcessError as err: warning_msg = err.output exit_code = err.returncode pass if exit_code != 0: kernellog.warn( app, "Error #%d when calling: %s" % (exit_code, " ".join(cmd))) if warning_msg: kernellog.warn( app, "Warning msg from %s: %s" % (cmd_name, str(warning_msg, 'utf-8'))) elif warning_msg: kernellog.verbose( app, "Warning msg from %s (likely harmless):\n%s" % (cmd_name, str(warning_msg, 'utf-8'))) return bool(exit_code == 0)
def setupTools(app): u""" Check available build tools and log some *verbose* messages. This function is called once, when the builder is initiated. """ global dot_cmd, convert_cmd # pylint: disable=W0603 kernellog.verbose(app, "kfigure: check installed tools ...") dot_cmd = which('dot') convert_cmd = which('convert') if dot_cmd: kernellog.verbose(app, "use dot(1) from: " + dot_cmd) else: kernellog.warn( app, "dot(1) not found, for better output quality install " "graphviz from https://www.graphviz.org") if convert_cmd: kernellog.verbose(app, "use convert(1) from: " + convert_cmd) else: kernellog.warn( app, "convert(1) not found, for SVG to PDF conversion install " "ImageMagick (https://www.imagemagick.org)")
def run(self): env = self.state.document.settings.env cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno'] # Pass the version string to kernel-doc, as it needs to use a different # dialect, depending what the C domain supports for each specific # Sphinx versions cmd += ['-sphinx-version', sphinx.__version__] filename = env.config.kerneldoc_srctree + '/' + self.arguments[0] export_file_patterns = [] # Tell sphinx of the dependency env.note_dependency(os.path.abspath(filename)) tab_width = self.options.get('tab-width', self.state.document.settings.tab_width) # 'function' is an alias of 'identifiers' if 'functions' in self.options: self.options['identifiers'] = self.options.get('functions') # FIXME: make this nicer and more robust against errors if 'export' in self.options: cmd += ['-export'] export_file_patterns = str(self.options.get('export')).split() elif 'internal' in self.options: cmd += ['-internal'] export_file_patterns = str(self.options.get('internal')).split() elif 'doc' in self.options: cmd += ['-function', str(self.options.get('doc'))] elif 'identifiers' in self.options: identifiers = self.options.get('identifiers').split() if identifiers: for i in identifiers: cmd += ['-function', i] else: cmd += ['-no-doc-sections'] if 'no-identifiers' in self.options: no_identifiers = self.options.get('no-identifiers').split() if no_identifiers: for i in no_identifiers: cmd += ['-nosymbol', i] for pattern in export_file_patterns: for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern): env.note_dependency(os.path.abspath(f)) cmd += ['-export-file', f] cmd += [filename] try: kernellog.verbose(env.app, 'calling kernel-doc \'%s\'' % (" ".join(cmd))) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8') if p.returncode != 0: sys.stderr.write(err) kernellog.warn( env.app, 'kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode)) return [ nodes.error(None, nodes.paragraph(text="kernel-doc missing")) ] elif env.config.kerneldoc_verbosity > 0: sys.stderr.write(err) lines = statemachine.string2lines(out, tab_width, convert_whitespace=True) result = ViewList() lineoffset = 0 line_regex = re.compile("^#define LINENO ([0-9]+)$") for line in lines: match = line_regex.search(line) if match: # sphinx counts lines from 0 lineoffset = int(match.group(1)) - 1 # we must eat our comments since the upset the markup else: doc = env.srcdir + "/" + env.docname + ":" + str( self.lineno) result.append(line, doc + ": " + filename, lineoffset) lineoffset += 1 node = nodes.section() self.do_parse(result, node) return node.children except Exception as e: # pylint: disable=W0703 kernellog.warn( env.app, 'kernel-doc \'%s\' processing failed with: %s' % (" ".join(cmd), str(e))) return [ nodes.error(None, nodes.paragraph(text="kernel-doc missing")) ]
def convert_image(img_node, translator, src_fname=None): """Convert a image node for the builder. Different builder prefer different image formats, e.g. *latex* builder prefer PDF while *html* builder prefer SVG format for images. This function handles output image formats in dependence of source the format (of the image) and the translator's output format. """ app = translator.builder.app fname, in_ext = path.splitext(path.basename(img_node['uri'])) if src_fname is None: src_fname = path.join(translator.builder.srcdir, img_node['uri']) if not path.exists(src_fname): src_fname = path.join(translator.builder.outdir, img_node['uri']) dst_fname = None # in kernel builds, use 'make SPHINXOPTS=-v' to see verbose messages kernellog.verbose(app, 'assert best format for: ' + img_node['uri']) if in_ext == '.dot': if not dot_cmd: kernellog.verbose( app, "dot from graphviz not available / include DOT raw.") img_node.replace_self(file2literal(src_fname)) elif translator.builder.format == 'latex': dst_fname = path.join(translator.builder.outdir, fname + '.pdf') img_node['uri'] = fname + '.pdf' img_node['candidates'] = {'*': fname + '.pdf'} elif translator.builder.format == 'html': dst_fname = path.join(translator.builder.outdir, translator.builder.imagedir, fname + '.svg') img_node['uri'] = path.join(translator.builder.imgpath, fname + '.svg') img_node['candidates'] = { '*': path.join(translator.builder.imgpath, fname + '.svg') } else: # all other builder formats will include DOT as raw img_node.replace_self(file2literal(src_fname)) elif in_ext == '.svg': if translator.builder.format == 'latex': if convert_cmd is None: kernellog.verbose( app, "no SVG to PDF conversion available / include SVG raw.") img_node.replace_self(file2literal(src_fname)) else: dst_fname = path.join(translator.builder.outdir, fname + '.pdf') img_node['uri'] = fname + '.pdf' img_node['candidates'] = {'*': fname + '.pdf'} if dst_fname: # the builder needs not to copy one more time, so pop it if exists. translator.builder.images.pop(img_node['uri'], None) _name = dst_fname[len(translator.builder.outdir) + 1:] if isNewer(dst_fname, src_fname): kernellog.verbose( app, "convert: {out}/%s already exists and is newer" % _name) else: ok = False mkdir(path.dirname(dst_fname)) if in_ext == '.dot': kernellog.verbose(app, 'convert DOT to: {out}/' + _name) ok = dot2format(app, src_fname, dst_fname) elif in_ext == '.svg': kernellog.verbose(app, 'convert SVG to: {out}/' + _name) ok = svg2pdf(app, src_fname, dst_fname) if not ok: img_node.replace_self(file2literal(src_fname))
def setupTools(app): u""" Check available build tools and log some *verbose* messages. This function is called once, when the builder is initiated. """ global dot_cmd, dot_Tpdf, convert_cmd, rsvg_convert_cmd # pylint: disable=W0603 global inkscape_cmd, inkscape_ver_one # pylint: disable=W0603 kernellog.verbose(app, "kfigure: check installed tools ...") dot_cmd = which('dot') convert_cmd = which('convert') rsvg_convert_cmd = which('rsvg-convert') inkscape_cmd = which('inkscape') if dot_cmd: kernellog.verbose(app, "use dot(1) from: " + dot_cmd) try: dot_Thelp_list = subprocess.check_output([dot_cmd, '-Thelp'], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as err: dot_Thelp_list = err.output pass dot_Tpdf_ptn = b'pdf' dot_Tpdf = re.search(dot_Tpdf_ptn, dot_Thelp_list) else: kernellog.warn( app, "dot(1) not found, for better output quality install " "graphviz from https://www.graphviz.org") if inkscape_cmd: kernellog.verbose(app, "use inkscape(1) from: " + inkscape_cmd) inkscape_ver = subprocess.check_output([inkscape_cmd, '--version'], stderr=subprocess.DEVNULL) ver_one_ptn = b'Inkscape 1' inkscape_ver_one = re.search(ver_one_ptn, inkscape_ver) convert_cmd = None rsvg_convert_cmd = None dot_Tpdf = False else: if convert_cmd: kernellog.verbose(app, "use convert(1) from: " + convert_cmd) else: kernellog.verbose( app, "Neither inkscape(1) nor convert(1) found.\n" "For SVG to PDF conversion, " "install either Inkscape (https://inkscape.org/) (preferred) or\n" "ImageMagick (https://www.imagemagick.org)") if rsvg_convert_cmd: kernellog.verbose(app, "use rsvg-convert(1) from: " + rsvg_convert_cmd) kernellog.verbose( app, "use 'dot -Tsvg' and rsvg-convert(1) for DOT -> PDF conversion" ) dot_Tpdf = False else: kernellog.verbose( app, "rsvg-convert(1) not found.\n" " SVG rendering of convert(1) is done by ImageMagick-native renderer." ) if dot_Tpdf: kernellog.verbose(app, "use 'dot -Tpdf' for DOT -> PDF conversion") else: kernellog.verbose( app, "use 'dot -Tsvg' and convert(1) for DOT -> PDF conversion")
def run(self): env = self.state.document.settings.env cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno'] filename = env.config.kerneldoc_srctree + '/' + self.arguments[0] export_file_patterns = [] # Tell sphinx of the dependency env.note_dependency(os.path.abspath(filename)) tab_width = self.options.get('tab-width', self.state.document.settings.tab_width) # FIXME: make this nicer and more robust against errors if 'export' in self.options: cmd += ['-export'] export_file_patterns = str(self.options.get('export')).split() elif 'internal' in self.options: cmd += ['-internal'] export_file_patterns = str(self.options.get('internal')).split() elif 'doc' in self.options: cmd += ['-function', str(self.options.get('doc'))] elif 'functions' in self.options: functions = self.options.get('functions').split() if functions: for f in functions: cmd += ['-function', f] else: cmd += ['-no-doc-sections'] for pattern in export_file_patterns: for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern): env.note_dependency(os.path.abspath(f)) cmd += ['-export-file', f] cmd += [filename] try: kernellog.verbose(env.app, 'calling kernel-doc \'%s\'' % (" ".join(cmd))) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8') if p.returncode != 0: sys.stderr.write(err) kernellog.warn(env.app, 'kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode)) return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))] elif env.config.kerneldoc_verbosity > 0: sys.stderr.write(err) lines = statemachine.string2lines(out, tab_width, convert_whitespace=True) result = ViewList() lineoffset = 0; line_regex = re.compile("^#define LINENO ([0-9]+)$") for line in lines: match = line_regex.search(line) if match: # sphinx counts lines from 0 lineoffset = int(match.group(1)) - 1 # we must eat our comments since the upset the markup else: result.append(line, filename, lineoffset) lineoffset += 1 node = nodes.section() self.do_parse(result, node) return node.children except Exception as e: # pylint: disable=W0703 kernellog.warn(env.app, 'kernel-doc \'%s\' processing failed with: %s' % (" ".join(cmd), str(e))) return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]