# HG changeset patch # User Paul Boddie # Date 1387234113 -3600 # Node ID 96f5b2a1fe8ec712467308b2e3642e2e4ba7e439 # Parent cfcb4d6c91f644d540dff4d991b92cf7c4161706 Added some support for XSL transformations to the Graphviz SVG output. diff -r cfcb4d6c91f6 -r 96f5b2a1fe8e parsers/graphviz.py --- a/parsers/graphviz.py Thu Apr 19 00:50:44 2012 +0200 +++ b/parsers/graphviz.py Mon Dec 16 23:48:33 2013 +0100 @@ -4,19 +4,21 @@ Based loosely on GNUPLOT parser by MoinMoin:KwonChanYoung @copyright: 2008 Wayne Tucker - @copyright: 2011, 2012 Paul Boddie + @copyright: 2011, 2012, 2013 Paul Boddie @copyright: 2012 Frederick Capovilla (Libéo) @license: GNU GPL, see COPYING for details. """ -__version__ = "0.2.3" +__version__ = "0.2.4" # Change this to the directory that the Graphviz binaries (dot, neato, etc.) # are installed in. -BINARY_PATH = '/usr/bin/' +BINARY_PATH = '/usr/bin/' +XSLT_PROCESSOR = "/usr/bin/xsltproc" +DIAGRAM_TOOLS_PATH = '/usr/local/share/diagram-tools' -from os.path import join +from os.path import join, exists from StringIO import StringIO import os import subprocess @@ -47,6 +49,9 @@ SVG_FORMATS = ['svg', 'svgz'] OUTPUT_FORMATS = IMAGE_FORMATS + SVG_FORMATS + \ ['ps', 'fig', 'mif', 'hpgl', 'pcl', 'dia', 'imap'] + TRANSFORMS = { + "notugly" : join(DIAGRAM_TOOLS_PATH, "notugly.xsl"), + } attach_regexp = re.compile( r"graphviz_" @@ -87,6 +92,7 @@ cmapx = None width = None height = None + transforms = [] raw_lines = self.raw.splitlines() for l in raw_lines: @@ -110,6 +116,13 @@ elif directive == 'cmapx': cmapx = wikiutil.escape(value) + elif directive == 'transform': + transform = value.lower() + if not self.TRANSFORMS.has_key(transform): + logging.warn('unknown transform %s' % transform) + else: + transforms.append(transform) + if not format in self.OUTPUT_FORMATS: raise NotImplementedError, "only formats %s are currently supported" % \ self.OUTPUT_FORMATS @@ -130,7 +143,7 @@ attrs = self.find_graph(digest, format) if not attrs: - attrs = self.graphviz(filter, self.raw, digest, format) + attrs = self.graphviz(filter, self.raw, digest, format, transforms) chart = self.get_chartname(digest, format, attrs) url = AttachFile.getAttachUrl(page.page_name, chart, request) @@ -140,7 +153,7 @@ if format in self.IMAGE_FORMATS: if cmapx: - request.write('\n' + self.graphviz(filter, self.raw, digest, "cmapx") + '\n') + request.write('\n' + self.graphviz(filter, self.raw, digest, "cmapx", transforms) + '\n') request.write(formatter.image(src="%s" % url, usemap="#%s" % cmapx, **self.get_format_attrs(attrs))) else: request.write(formatter.image(src="%s" % url, alt="graphviz image", **self.get_format_attrs(attrs))) @@ -203,7 +216,7 @@ if chart_date < page_date: os.remove(fullpath) - def graphviz(self, filter, graph_def, digest, format): + def graphviz(self, filter, graph_def, digest, format, transforms): """ Using the 'filter' with the given 'graph_def' (and 'digest'), generate @@ -211,39 +224,42 @@ """ need_output = format in ("cmapx", "svg") + program = join(BINARY_PATH, filter) # Either write the output straight to a file. if not need_output: chart = self.get_chartname(digest, format) filename = join(self.attach_dir, chart).encode(config.charset) - - p = subprocess.Popen([ - join(BINARY_PATH, filter), '-T%s' % format, '-o%s' % filename - ], - shell=False, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + options = ['-o%s' % filename] # Or intercept the output. else: - p = subprocess.Popen([ - join(BINARY_PATH, filter), '-T%s' % format - ], - shell=False, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + options = [] + + start = p = subprocess.Popen( + [program, '-T%s' % format] + options, + shell=False, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) - (stdoutdata, stderrdata) = p.communicate(input=graph_def.encode('utf-8')) + if format == "svg" and transforms: + p = self.transform_output(p, transforms) + + start.stdin.write(graph_def.encode('utf-8')) + + if p is not start: + start.stdin.close() + + (stdoutdata, stderrdata) = p.communicate() # Graph data always goes via standard output so that we can extract the # width and height if possible. if need_output: - output, attrs = self.process_output(StringIO(stdoutdata), format) + output, attrs = self.process_output(StringIO(stdoutdata), format, transforms) else: output, attrs = None, {} @@ -252,6 +268,9 @@ errors = stderrdata if len(errors) > 0: + logging.warn(errors) + + if p.wait() != 0: raise GraphVizError, errors # Return the output for imagemaps. @@ -275,7 +294,24 @@ return attrs - def process_output(self, output, format): + def transform_output(self, process, transforms): + + # First, transform the output, if requested. + + if exists(XSLT_PROCESSOR): + for transform in transforms: + process = subprocess.Popen( + [XSLT_PROCESSOR, self.TRANSFORMS[transform], "-"], + shell=False, + stdin=process.stdout, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + else: + logging.warn('XSLT processor not found at %s' % XSLT_PROCESSOR) + + return process + + def process_output(self, output, format, transforms): "Process graph 'output' in the given 'format'."