1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/README.txt Sat Jan 14 19:00:46 2012 +0100
1.3 @@ -0,0 +1,65 @@
1.4 +Basic Usage
1.5 +-----------
1.6 +
1.7 +Embed a visualization of a graph in a wiki page:
1.8 +
1.9 +{{{#!graphviz
1.10 +digraph G {
1.11 + A -> B;
1.12 +};
1.13 +}}}
1.14 +
1.15 +Advanced Usage
1.16 +--------------
1.17 +
1.18 +This parser will check the first lines of the Graphviz data for C++ style
1.19 +comments instructing it to use a different filter (dot, neato, twopi, circo,
1.20 +or fdp - see http://graphviz.org/ for more info), use a different format for
1.21 +the output (see the FORMATS list in the Parser class), or to generate and pass
1.22 +a client-side image map.
1.23 +
1.24 +Options:
1.25 +
1.26 +filter - the filter to use (see Parser.FILTERS)
1.27 +format - the output format (see Parser.FORMATS)
1.28 +cmapx - the map name to use for the client-side image map; this must match
1.29 + the graph name in the graph definition and shouldn't conflict with
1.30 + any other graphs that are used on the same page; for SVG images, the
1.31 + cmapx option is superfluous since SVG supports linking natively and
1.32 + Graphviz converts "href" attributes appropriately
1.33 +
1.34 +Embed a visualization of a graph in a wiki page, using the dot filter and
1.35 +providing a client-side image map (the filter=dot and format=png options are
1.36 +redundant since those are the defaults for this parser):
1.37 +
1.38 +{{{#!graphviz
1.39 +//filter=dot
1.40 +//format=png
1.41 +//cmapx=DocumentationMap
1.42 +digraph DocumentationMap {
1.43 + FrontPage [href="FrontPage", root=true];
1.44 + HelpOnEditing [href="HelpOnEditing"];
1.45 + SyntaxReference [href="SyntaxReference"];
1.46 + WikiSandBox [href="WikiSandBox", color="grey"];
1.47 + MoinMoin [href="http://moinmo.in"];
1.48 + FrontPage -> WikiSandBox;
1.49 + FrontPage -> MoinMoin;
1.50 + WikiSandBox -> HelpOnEditing;
1.51 + WikiSandBox -> SyntaxReference;
1.52 + SyntaxReference -> FrontPage;
1.53 +};
1.54 +}}}
1.55 +
1.56 +Known Bugs
1.57 +----------
1.58 +
1.59 + - Hasn't been thoroughly checked for potential methods of injecting
1.60 + arbitrary HTML into the output.
1.61 + - Only compatible with HTML rendering
1.62 + - May not use all of the MoinMoin interfaces properly - this is a
1.63 + quick hack based on looking at an example and digging through the
1.64 + MoinMoin source. The MoinMoin development docs haven't been
1.65 + consulted (yet).
1.66 + - Comments must start at the beginning of the graphviz block, and at the
1.67 + beginning of their respective lines. They must also not contain
1.68 + any extra whitespace surrounding the = sign.
2.1 --- a/graphviz.py Sat Jan 14 16:35:38 2012 +0100
2.2 +++ b/graphviz.py Sat Jan 14 19:00:46 2012 +0100
2.3 @@ -8,74 +8,12 @@
2.4 @license: GNU GPL, see COPYING for details.
2.5 """
2.6
2.7 -"""
2.8 - BASIC USAGE:
2.9 -
2.10 - embed a visualization of a graph in a wiki page:
2.11 -
2.12 -{{{#!graphviz
2.13 -digraph G {
2.14 - A -> B;
2.15 -};
2.16 -}}}
2.17 -
2.18 - ADVANCED USAGE:
2.19 -
2.20 - This parser will check the first lines of the Graphviz data for C++ style
2.21 - comments instructing it to use a different filter (dot, neato, twopi,
2.22 - circo, or fdp - see http://graphviz.org/ for more info), use a different
2.23 - format for the output (see the FORMATS list in the Parser class below),
2.24 - or to generate and pass a client-side image map.
2.25 -
2.26 - Options:
2.27 - filter - the filter to use (see Parser.FILTERS)
2.28 - format - the output format (see Parser.FORMATS)
2.29 - cmapx - the map name to use for the client-side image map. Must match
2.30 - the graph name in the graph definition and shouldn't conflict
2.31 - with any other graphs that are used on the same page.
2.32 -
2.33 - embed a visualization of a graph in a wiki page, using the dot filter and
2.34 - providing a client-side image map (the filter=dot and format=png options are
2.35 - redundant since those are the defaults for this parser):
2.36 -
2.37 -{{{#!graphviz
2.38 -//filter=dot
2.39 -//format=png
2.40 -//cmapx=DocumentationMap
2.41 -digraph DocumentationMap {
2.42 - FrontPage [href="FrontPage", root=true];
2.43 - HelpOnEditing [href="HelpOnEditing"];
2.44 - SyntaxReference [href="SyntaxReference"];
2.45 - WikiSandBox [href="WikiSandBox", color="grey"];
2.46 - MoinMoin [href="http://moinmo.in"];
2.47 - FrontPage -> WikiSandBox;
2.48 - FrontPage -> MoinMoin;
2.49 - WikiSandBox -> HelpOnEditing;
2.50 - WikiSandBox -> SyntaxReference;
2.51 - SyntaxReference -> FrontPage;
2.52 -};
2.53 -}}}
2.54 -
2.55 -
2.56 - KNOWN BUGS:
2.57 - - Hasn't been thoroughly checked for potential methods of injecting
2.58 - arbitrary HTML into the output.
2.59 - - Only compatible with HTML rendering
2.60 - - May not use all of the MoinMoin interfaces properly - this is a
2.61 - quick hack based on looking at an example and digging through the
2.62 - MoinMoin source. The MoinMoin development docs haven't been
2.63 - consulted (yet).
2.64 - - Comments must start at the beginning of the graphviz block, and at the
2.65 - beginning of their respective lines. They must also not contain
2.66 - any extra whitespace surrounding the = sign.
2.67 -
2.68 -"""
2.69 -
2.70 # Change this to the directory that the Graphviz binaries (dot, neato, etc.)
2.71 # are installed in.
2.72
2.73 BINARY_PATH = '/usr/bin'
2.74
2.75 +from os.path import join
2.76 import os
2.77 import subprocess
2.78 import sha
2.79 @@ -91,19 +29,20 @@
2.80 class GraphVizError(RuntimeError):
2.81 pass
2.82
2.83 -Dependencies = []
2.84 +Dependencies = ["pages"]
2.85
2.86 class Parser:
2.87 - """Uses the Graphviz programs to create a visualization of a graph."""
2.88 +
2.89 + "Uses the Graphviz programs to create a visualization of a graph."
2.90 +
2.91 + extensions = []
2.92 + Dependencies = Dependencies
2.93
2.94 FILTERS = ['dot', 'neato', 'twopi', 'circo', 'fdp']
2.95 IMAGE_FORMATS = ['png', 'gif']
2.96 - OBJECT_FORMATS = ['svg', 'svgz']
2.97 - OUTPUT_FORMATS = IMAGE_FORMATS + OBJECT_FORMATS
2.98 - FORMATS = OUTPUT_FORMATS + \
2.99 - ['ps', 'fig', 'mif', 'hpgl', 'pcl', 'dia', 'imap', 'cmapx']
2.100 - extensions = []
2.101 - Dependencies = Dependencies
2.102 + SVG_FORMATS = ['svg', 'svgz']
2.103 + OUTPUT_FORMATS = IMAGE_FORMATS + SVG_FORMATS + \
2.104 + ['ps', 'fig', 'mif', 'hpgl', 'pcl', 'dia', 'imap']
2.105
2.106 attach_regexp = re.compile(
2.107 r"graphviz_"
2.108 @@ -136,7 +75,7 @@
2.109
2.110 request.flush() # to identify error text
2.111
2.112 - self.filter = Parser.FILTERS[0]
2.113 + filter = self.FILTERS[0]
2.114 format = 'png'
2.115 cmapx = None
2.116 width = None
2.117 @@ -153,47 +92,55 @@
2.118
2.119 if directive == 'filter':
2.120 filter = value.lower()
2.121 - if filter in Parser.FILTERS:
2.122 - self.filter = filter
2.123 - else:
2.124 + if filter not in self.FILTERS:
2.125 logging.warn('unknown filter %s' % filter)
2.126
2.127 elif directive == 'format':
2.128 value = value.lower()
2.129 - if value in Parser.FORMATS:
2.130 + if value in self.OUTPUT_FORMATS:
2.131 format = value
2.132
2.133 elif directive == 'cmapx':
2.134 cmapx = wikiutil.escape(value)
2.135
2.136 - if not format in Parser.OUTPUT_FORMATS:
2.137 + if not format in self.OUTPUT_FORMATS:
2.138 raise NotImplementedError, "only formats %s are currently supported" % \
2.139 - Parser.OUTPUT_FORMATS
2.140 + self.OUTPUT_FORMATS
2.141
2.142 - if cmapx:
2.143 - if not format in Parser.IMAGE_FORMATS:
2.144 - logging.warn('format %s is incompatible with cmapx option' % format)
2.145 - cmapx = None
2.146 + if cmapx and not format in self.IMAGE_FORMATS:
2.147 + logging.warn('format %s is incompatible with cmapx option' % format)
2.148 + cmapx = None
2.149
2.150 digest = sha.new(self.raw).hexdigest()
2.151
2.152 - self.pagename = formatter.page.page_name
2.153 - self.attach_dir = AttachFile.getAttachDir(request, self.pagename, create=1)
2.154 + # Make sure that an attachments directory exists and that old graphs are
2.155 + # deleted.
2.156 +
2.157 + self.attach_dir = AttachFile.getAttachDir(request, page.page_name, create=1)
2.158 self.delete_old_graphs(formatter)
2.159
2.160 + # Find the details of the graph, rendering a new graph if necessary.
2.161 +
2.162 attrs = self.find_graph(digest, format)
2.163 if not attrs:
2.164 - attrs = self.graphviz(self.raw, digest, format)
2.165 + attrs = self.graphviz(filter, self.raw, digest, format)
2.166
2.167 chart = self.get_chartname(digest, format, attrs)
2.168 - url = AttachFile.getAttachUrl(self.pagename, chart, request)
2.169 + url = AttachFile.getAttachUrl(page.page_name, chart, request)
2.170
2.171 - if format in Parser.IMAGE_FORMATS:
2.172 + # Images are displayed using the HTML "img" element (or equivalent)
2.173 + # and may provide an imagemap.
2.174 +
2.175 + if format in self.IMAGE_FORMATS:
2.176 if cmapx:
2.177 - request.write('\n' + self.graphviz(self.raw, digest, "cmapx") + '\n')
2.178 + request.write('\n' + self.graphviz(filter, self.raw, digest, "cmapx") + '\n')
2.179 request.write(formatter.image(src="%s" % url, usemap="#%s" % cmapx, **self.get_format_attrs(attrs)))
2.180 else:
2.181 request.write(formatter.image(src="%s" % url, alt="graphviz image", **self.get_format_attrs(attrs)))
2.182 +
2.183 + # Other objects are embedded using the HTML "object" element (or
2.184 + # equivalent).
2.185 +
2.186 else:
2.187 request.write(formatter.transclusion(1, data=url, **self.get_format_attrs(attrs)))
2.188 request.write(formatter.text(_("graphviz image")))
2.189 @@ -203,7 +150,7 @@
2.190
2.191 "Find an existing graph using 'digest' and 'format'."
2.192
2.193 - attach_files = AttachFile._get_files(self.request, self.pagename)
2.194 + attach_files = AttachFile._get_files(self.request, self.request.page.page_name)
2.195
2.196 for chart in attach_files:
2.197 match = self.attach_regexp.match(chart)
2.198 @@ -237,23 +184,26 @@
2.199 except KeyError, ex:
2.200 return
2.201
2.202 - attach_files = AttachFile._get_files(self.request, self.pagename)
2.203 + attach_files = AttachFile._get_files(self.request, self.request.page.page_name)
2.204
2.205 for chart in attach_files:
2.206 match = self.attach_regexp.match(chart)
2.207
2.208 - if match and match.group("format") in Parser.FORMATS:
2.209 - fullpath = os.path.join(self.attach_dir, chart).encode(config.charset)
2.210 + if match and match.group("format") in self.OUTPUT_FORMATS:
2.211 + fullpath = join(self.attach_dir, chart).encode(config.charset)
2.212 st = os.stat(fullpath)
2.213 chart_date = self.request.user.getFormattedDateTime(st.st_mtime)
2.214 if chart_date < page_date:
2.215 os.remove(fullpath)
2.216
2.217 - def graphviz(self, graph_def, digest, format):
2.218 + def graphviz(self, filter, graph_def, digest, format):
2.219
2.220 - "Using the 'graph_def' and 'digest', generate output in the given 'format'."
2.221 + """
2.222 + Using the 'filter' with the given 'graph_def' (and 'digest'), generate
2.223 + output in the given 'format'.
2.224 + """
2.225
2.226 - p = subprocess.Popen(['%s/%s' % (BINARY_PATH, self.filter), '-T%s' % format], shell=False, \
2.227 + p = subprocess.Popen([join(BINARY_PATH, filter), '-T%s' % format], shell=False, \
2.228 stdin=subprocess.PIPE, \
2.229 stdout=subprocess.PIPE, \
2.230 stderr=subprocess.PIPE)
2.231 @@ -277,7 +227,7 @@
2.232
2.233 if format != "cmapx":
2.234 chart = self.get_chartname(digest, format, attrs)
2.235 - filename = os.path.join(self.attach_dir, chart).encode(config.charset)
2.236 + filename = join(self.attach_dir, chart).encode(config.charset)
2.237
2.238 f = open(filename, "wb")
2.239 try: