Ticket #3542: graphvizplugin-misc-fixes-r4341.patch
| File graphvizplugin-misc-fixes-r4341.patch, 9.7 kB (added by cboos, 3 months ago) |
|---|
-
graphviz/graphviz.py
old new 16 16 __version__ = '0.7.2' 17 17 18 18 19 try: 20 from cStringIO import StringIO 21 except ImportError: 22 from StringIO import StringIO 19 from StringIO import StringIO 20 import locale 23 21 import sha 24 22 import os 25 23 import sys … … 27 25 import inspect 28 26 import subprocess 29 27 28 from trac.config import Option 30 29 from trac.core import * 31 30 from trac.wiki.api import IWikiMacroProvider 32 31 from trac.mimeview.api import IHTMLPreviewRenderer, MIME_MAP 33 32 from trac.util import escape 33 from trac.util.text import to_unicode 34 34 from trac.wiki.formatter import wiki_to_oneliner 35 35 from trac.web.api import IRequestHandler 36 36 … … 47 47 """ 48 48 implements(IWikiMacroProvider, IHTMLPreviewRenderer, IRequestHandler) 49 49 50 cache_dir_option = Option("graphviz", "cache_dir", "gvcache", 51 """The directory that will be used to cache the generated images 52 (note that the directory must exist). 53 If not given as an absolute path, the path will be relative to 54 the Trac environment's directory. 55 """) 56 57 encoding = Option("graphviz", "encoding", 'utf-8', 58 """The encoding which should be used for communicating with 59 Graphviz. 60 """) 61 50 62 # Available formats and processors, default first (dot/png) 51 63 Processors = ['dot', 'neato', 'twopi', 'circo', 'fdp'] 52 64 Bitmap_Formats = ['png', 'jpg', 'gif'] … … 176 188 buf.write('<p>Graphviz macro processor error: requested format (%s) not valid.</p>' % self.out_format) 177 189 return buf.getvalue() 178 190 179 encoding = 'utf-8' 180 if type(content) == type(u''): 181 content = content.encode(encoding) 182 sha_text = self.processor.encode(encoding) + self.processor_options.encode(encoding) + content 183 184 else: 185 sha_text = self.processor + self.processor_options + content 186 191 sha_text = self.processor + unicode(self.processor_options) + content 187 192 sha_key = sha.new(sha_text).hexdigest() 188 193 img_name = '%s.%s.%s' % (sha_key, self.processor, self.out_format) # cache: hash.<dot>.<png> 189 194 img_path = os.path.join(self.cache_dir, img_name) … … 200 205 #self.log.debug('render_macro.URL_in_graph: %s' % str(URL_in_graph)) 201 206 if URL_in_graph: # translate wiki TracLinks in URL 202 207 #self.log.debug('content: %s' % content) 203 content = re.sub(r'URL="(.*?)"', self.expand_wiki_links, unicode(content, 'utf-8'))208 content = self.expand_wiki_links(content) 204 209 205 206 210 # Antialias PNGs with rsvg, if requested 207 211 if self.out_format == 'png' and self.png_anti_alias == True: 208 212 # 1. SVG output 209 cmd = [proc_cmd, self.processor_options, '-Tsvg', '-o%s.svg' % img_path] 213 cmd = [proc_cmd] + self.processor_options + \ 214 ['-Tsvg', '-o%s.svg' % img_path] 210 215 #self.log.debug('render_macro: svg output - running command %s' % cmd) 211 216 out, err = self.launch(cmd, content) 212 217 if len(out) or len(err): … … 222 227 return self.show_err(msg).getvalue() 223 228 224 229 else: # Render other image formats 225 cmd = [proc_cmd, self.processor_options, '-T%s' % self.out_format, '-o%s' % img_path] 230 cmd = [proc_cmd] + self.processor_options + \ 231 ['-T%s' % self.out_format, '-o%s' % img_path] 226 232 #self.log.debug('render_macro: render other image formats - running command %s' % cmd) 227 233 out, err = self.launch(cmd, content) 228 234 if len(out) or len(err): … … 234 240 235 241 # Create the map if not in cache 236 242 if not os.path.exists(map_path): 237 cmd = [proc_cmd, self.processor_options, '-Tcmap', '-o%s' % map_path] 243 cmd = [proc_cmd] + self.processor_options + \ 244 ['-Tcmap', '-o%s' % map_path] 238 245 #self.log.debug('render_macro: create map if not in cache - running command %s' % cmd) 239 246 out, err = self.launch(cmd, content) 240 247 if len(out) or len(err): … … 269 276 buf.write('<object data="%s/graphviz/%s" type="image/svg+xml" %s><embed src="%s/graphviz/%s" type="image/svg+xml" %s></embed></object>' % (req.base_url, img_name, dimensions, req.base_url, img_name, dimensions)) 270 277 271 278 # for binary formats, add map 272 elif URL_in_graph :279 elif URL_in_graph and os.path.exists(map_path): 273 280 f = open(map_path, 'r') 274 281 map = f.readlines() 275 282 f.close() … … 284 291 return buf.getvalue() 285 292 286 293 287 def expand_wiki_links(self, match): 288 wiki_url = match.groups()[0] # TracLink ([1], source:file/, ...) 294 def expand_wiki_links(self, content): 295 """Expand TracLinks that follow all URL= patterns.""" 296 return re.sub(r'URL="(.*?)"', self._expand_wiki_links, content) 297 298 def _expand_wiki_links(self, match): 299 wiki_url = match.groups()[0] # TracLink ([1], source:file/, ...) 289 300 #self.log.debug('wiki_url: %s' % wiki_url) 290 301 #self.log.debug('self.env: %s' % str(self.env)) 291 302 #self.log.debug('self.formatter.req: %s' % str(self.formatter.req)) … … 313 324 return (True, self.show_err(msg)) 314 325 315 326 # check for the cache_dir entry 316 self.cache_dir = self.c onfig.get('graphviz', 'cache_dir')327 self.cache_dir = self.cache_dir_option 317 328 if not self.cache_dir: 318 329 msg = 'The [graphviz] section is missing the cache_dir field.' 319 330 return True, self.show_err(msg) 320 331 332 if not os.path.isabs(self.cache_dir): 333 self.cache_dir = os.path.join(self.env.path, self.cache_dir) 334 321 335 if not os.path.exists(self.cache_dir): 322 msg = 'The cache_dir is set to "%s" but that path does not exist.' % self.cache_dir 336 msg = "The cache_dir '%s' doesn't exist, please create it." % \ 337 self.cache_dir 323 338 return True, self.show_err(msg) 324 339 #self.log.debug('self.cache_dir: %s' % self.cache_dir) 325 340 … … 379 394 #self.log.debug('self.rsvg_path: %s' % self.rsvg_path) 380 395 381 396 # get default graph/node/edge attributes 382 self.processor_options = '' 383 default_attributes = [ o for o in self.config.options('graphviz') if o[0].startswith('default_') ] 384 if default_attributes: 385 graph_attributes = [ o for o in default_attributes if o[0].startswith('default_graph_') ] 386 node_attributes = [ o for o in default_attributes if o[0].startswith('default_node_') ] 387 edge_attributes = [ o for o in default_attributes if o[0].startswith('default_edge_') ] 388 if graph_attributes: 389 self.processor_options += " ".join([ "-G" + o[0].replace('default_graph_', '') + "=" + o[1] for o in graph_attributes]) + " " 390 if node_attributes: 391 self.processor_options += " ".join([ "-N" + o[0].replace('default_node_', '') + "=" + o[1] for o in node_attributes]) + " " 392 if edge_attributes: 393 self.processor_options += " ".join([ "-E" + o[0].replace('default_edge_', '') + "=" + o[1] for o in edge_attributes]) 397 self.processor_options = [] 398 defaults = [opt for opt in self.config.options('graphviz') 399 if opt[0].startswith('default_')] 400 for name, value in defaults: 401 for prefix, optkey in [ 402 ('default_graph_', '-G'), 403 ('default_node_', '-N'), 404 ('default_edge_', '-E')]: 405 if name.startswith(prefix): 406 self.processor_options.append("%s%s=%s" % 407 (optkey, name.replace(prefix,''), value)) 394 408 395 396 409 # check if we should run the cache manager 397 410 self.cache_manager = self.boolean(self.config.get('graphviz', 'cache_manager', False)) 398 411 if self.cache_manager: … … 421 434 422 435 def launch(self, cmd, input): 423 436 """Launch a process (cmd), and returns exitcode, stdout + stderr""" 424 p = subprocess.Popen(cmd, 437 # Note: subprocess.Popen doesn't support unicode options arguments 438 # (http://bugs.python.org/issue1759845) so we have to encode them. 439 # We use the same encoding as the one sys.argv is supposed to have, see 440 # http://mail.python.org/pipermail/python-list/2006-October/410404.html 441 cmdline_encoding = locale.getpreferredencoding() 442 encoded_cmd = [] 443 for arg in cmd: 444 if isinstance(arg, unicode): 445 arg = arg.encode(cmdline_encoding, 'replace') 446 encoded_cmd.append(arg) 447 p = subprocess.Popen(encoded_cmd, 425 448 stdin=subprocess.PIPE, 426 449 stdout=subprocess.PIPE, 427 450 stderr=subprocess.PIPE) 428 451 429 452 if input: 430 p.stdin.write(input )453 p.stdin.write(input.encode(self.encoding)) 431 454 p.stdin.close() 432 455 out = p.stdout.read() 433 456 err = p.stderr.read() … … 440 463 buf.write('<div id="content" class="error"><div class="message"> \n\ 441 464 <strong>Graphviz macro processor has detected an error. Please fix the problem before continuing.</strong> \n\ 442 465 <pre>%s</pre> \n\ 443 </div></div>' % escape( msg))466 </div></div>' % escape(to_unicode(msg))) 444 467 self.log.error(msg) 445 468 return buf 446 469
