1.1 --- a/parsers/graphviz.py Thu Apr 19 00:50:44 2012 +0200
1.2 +++ b/parsers/graphviz.py Mon Dec 16 23:48:33 2013 +0100
1.3 @@ -4,19 +4,21 @@
1.4 Based loosely on GNUPLOT parser by MoinMoin:KwonChanYoung
1.5
1.6 @copyright: 2008 Wayne Tucker
1.7 - @copyright: 2011, 2012 Paul Boddie <paul@boddie.org.uk>
1.8 + @copyright: 2011, 2012, 2013 Paul Boddie <paul@boddie.org.uk>
1.9 @copyright: 2012 Frederick Capovilla (Libéo) <fcapovilla@live.ca>
1.10 @license: GNU GPL, see COPYING for details.
1.11 """
1.12
1.13 -__version__ = "0.2.3"
1.14 +__version__ = "0.2.4"
1.15
1.16 # Change this to the directory that the Graphviz binaries (dot, neato, etc.)
1.17 # are installed in.
1.18
1.19 -BINARY_PATH = '/usr/bin/'
1.20 +BINARY_PATH = '/usr/bin/'
1.21 +XSLT_PROCESSOR = "/usr/bin/xsltproc"
1.22 +DIAGRAM_TOOLS_PATH = '/usr/local/share/diagram-tools'
1.23
1.24 -from os.path import join
1.25 +from os.path import join, exists
1.26 from StringIO import StringIO
1.27 import os
1.28 import subprocess
1.29 @@ -47,6 +49,9 @@
1.30 SVG_FORMATS = ['svg', 'svgz']
1.31 OUTPUT_FORMATS = IMAGE_FORMATS + SVG_FORMATS + \
1.32 ['ps', 'fig', 'mif', 'hpgl', 'pcl', 'dia', 'imap']
1.33 + TRANSFORMS = {
1.34 + "notugly" : join(DIAGRAM_TOOLS_PATH, "notugly.xsl"),
1.35 + }
1.36
1.37 attach_regexp = re.compile(
1.38 r"graphviz_"
1.39 @@ -87,6 +92,7 @@
1.40 cmapx = None
1.41 width = None
1.42 height = None
1.43 + transforms = []
1.44
1.45 raw_lines = self.raw.splitlines()
1.46 for l in raw_lines:
1.47 @@ -110,6 +116,13 @@
1.48 elif directive == 'cmapx':
1.49 cmapx = wikiutil.escape(value)
1.50
1.51 + elif directive == 'transform':
1.52 + transform = value.lower()
1.53 + if not self.TRANSFORMS.has_key(transform):
1.54 + logging.warn('unknown transform %s' % transform)
1.55 + else:
1.56 + transforms.append(transform)
1.57 +
1.58 if not format in self.OUTPUT_FORMATS:
1.59 raise NotImplementedError, "only formats %s are currently supported" % \
1.60 self.OUTPUT_FORMATS
1.61 @@ -130,7 +143,7 @@
1.62
1.63 attrs = self.find_graph(digest, format)
1.64 if not attrs:
1.65 - attrs = self.graphviz(filter, self.raw, digest, format)
1.66 + attrs = self.graphviz(filter, self.raw, digest, format, transforms)
1.67
1.68 chart = self.get_chartname(digest, format, attrs)
1.69 url = AttachFile.getAttachUrl(page.page_name, chart, request)
1.70 @@ -140,7 +153,7 @@
1.71
1.72 if format in self.IMAGE_FORMATS:
1.73 if cmapx:
1.74 - request.write('\n' + self.graphviz(filter, self.raw, digest, "cmapx") + '\n')
1.75 + request.write('\n' + self.graphviz(filter, self.raw, digest, "cmapx", transforms) + '\n')
1.76 request.write(formatter.image(src="%s" % url, usemap="#%s" % cmapx, **self.get_format_attrs(attrs)))
1.77 else:
1.78 request.write(formatter.image(src="%s" % url, alt="graphviz image", **self.get_format_attrs(attrs)))
1.79 @@ -203,7 +216,7 @@
1.80 if chart_date < page_date:
1.81 os.remove(fullpath)
1.82
1.83 - def graphviz(self, filter, graph_def, digest, format):
1.84 + def graphviz(self, filter, graph_def, digest, format, transforms):
1.85
1.86 """
1.87 Using the 'filter' with the given 'graph_def' (and 'digest'), generate
1.88 @@ -211,39 +224,42 @@
1.89 """
1.90
1.91 need_output = format in ("cmapx", "svg")
1.92 + program = join(BINARY_PATH, filter)
1.93
1.94 # Either write the output straight to a file.
1.95
1.96 if not need_output:
1.97 chart = self.get_chartname(digest, format)
1.98 filename = join(self.attach_dir, chart).encode(config.charset)
1.99 -
1.100 - p = subprocess.Popen([
1.101 - join(BINARY_PATH, filter), '-T%s' % format, '-o%s' % filename
1.102 - ],
1.103 - shell=False,
1.104 - stdin=subprocess.PIPE,
1.105 - stdout=subprocess.PIPE,
1.106 - stderr=subprocess.PIPE)
1.107 + options = ['-o%s' % filename]
1.108
1.109 # Or intercept the output.
1.110
1.111 else:
1.112 - p = subprocess.Popen([
1.113 - join(BINARY_PATH, filter), '-T%s' % format
1.114 - ],
1.115 - shell=False,
1.116 - stdin=subprocess.PIPE,
1.117 - stdout=subprocess.PIPE,
1.118 - stderr=subprocess.PIPE)
1.119 + options = []
1.120 +
1.121 + start = p = subprocess.Popen(
1.122 + [program, '-T%s' % format] + options,
1.123 + shell=False,
1.124 + stdin=subprocess.PIPE,
1.125 + stdout=subprocess.PIPE,
1.126 + stderr=subprocess.PIPE)
1.127
1.128 - (stdoutdata, stderrdata) = p.communicate(input=graph_def.encode('utf-8'))
1.129 + if format == "svg" and transforms:
1.130 + p = self.transform_output(p, transforms)
1.131 +
1.132 + start.stdin.write(graph_def.encode('utf-8'))
1.133 +
1.134 + if p is not start:
1.135 + start.stdin.close()
1.136 +
1.137 + (stdoutdata, stderrdata) = p.communicate()
1.138
1.139 # Graph data always goes via standard output so that we can extract the
1.140 # width and height if possible.
1.141
1.142 if need_output:
1.143 - output, attrs = self.process_output(StringIO(stdoutdata), format)
1.144 + output, attrs = self.process_output(StringIO(stdoutdata), format, transforms)
1.145 else:
1.146 output, attrs = None, {}
1.147
1.148 @@ -252,6 +268,9 @@
1.149 errors = stderrdata
1.150
1.151 if len(errors) > 0:
1.152 + logging.warn(errors)
1.153 +
1.154 + if p.wait() != 0:
1.155 raise GraphVizError, errors
1.156
1.157 # Return the output for imagemaps.
1.158 @@ -275,7 +294,24 @@
1.159
1.160 return attrs
1.161
1.162 - def process_output(self, output, format):
1.163 + def transform_output(self, process, transforms):
1.164 +
1.165 + # First, transform the output, if requested.
1.166 +
1.167 + if exists(XSLT_PROCESSOR):
1.168 + for transform in transforms:
1.169 + process = subprocess.Popen(
1.170 + [XSLT_PROCESSOR, self.TRANSFORMS[transform], "-"],
1.171 + shell=False,
1.172 + stdin=process.stdout,
1.173 + stdout=subprocess.PIPE,
1.174 + stderr=subprocess.PIPE)
1.175 + else:
1.176 + logging.warn('XSLT processor not found at %s' % XSLT_PROCESSOR)
1.177 +
1.178 + return process
1.179 +
1.180 + def process_output(self, output, format, transforms):
1.181
1.182 "Process graph 'output' in the given 'format'."
1.183