Changeset 1601

Show
Ignore:
Timestamp:
11/25/06 18:00:34 (2 years ago)
Author:
pkropf
Message:

GraphvizPlugin:

Merged changes from the v0.6 branch that happened after the v0.7 branch was created.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • graphvizplugin/branches/v0.7

    • Property svn:ignore changed from
      build
      dist
      to
      build
      dist
      graphviz.egg-info
  • graphvizplugin/branches/v0.7/graphviz/graphviz.py

    r1600 r1601  
    2929from trac.core import * 
    3030from trac.wiki.api import IWikiMacroProvider 
     31from trac.mimeview.api import IHTMLPreviewRenderer, MIME_MAP 
     32from trac.web.main import IRequestHandler 
    3133from trac.util import escape 
    3234from trac.wiki.formatter import wiki_to_oneliner 
     
    3436 
    3537 
    36  
    3738_TRUE_VALUES = ('yes', 'true', 'on', 'aye', '1', 1, True) 
    38  
    3939 
    4040 
    4141class GraphvizMacro(Component): 
    4242    """ 
    43     Blah, blah, blah. 
     43    GraphvizMacro (http://trac-hacks.org/wiki/GraphvizPlugin) provides 
     44    a plugin for Trac to render graphviz (http://www.graphviz.org/) 
     45    drawings within a Trac wiki page. 
    4446    """ 
    45     implements(IWikiMacroProvider, IRequestHandler) 
     47    implements(IWikiMacroProvider, IHTMLPreviewRenderer, IRequestHandler) 
    4648 
    4749    # Available formats and processors, default first (dot/png) 
     
    5052    vector_formats = ['svg', 'svgz'] 
    5153    formats = bitmap_formats + vector_formats  
     54    cmd_paths = {'linux2':   '/usr/bin', 
     55                 'win32':    'c:\\Program Files\\ATT\\Graphviz\\bin', 
     56                 'freebsd6': '/usr/local/bin', 
     57                 'freebsd5': '/usr/local/bin', 
     58                 } 
    5259 
    5360    def __init__(self): 
     
    5966    def get_macros(self): 
    6067        """Return an iterable that provides the names of the provided macros.""" 
     68        self.load_config() 
    6169        for p in ['.' + p for p in GraphvizMacro.processors] + ['']:  
    6270            for f in ['/' + f for f in GraphvizMacro.formats] + ['']: 
     
    6573 
    6674    def get_macro_description(self, name): 
    67         """Return a plain text description of the macro with the specified name.""" 
    68         return inspect.getdoc(GraphvizMacro) 
     75        """ 
     76        Return a plain text description of the macro with the 
     77        specified name. Only return a description for the base 
     78        graphviz macro. All the other variants (graphviz/png, 
     79        graphviz/svg, etc.) will have no description. This will 
     80        cleanup the WikiMacros page a bit. 
     81        """ 
     82        if name == 'graphviz': 
     83            return inspect.getdoc(GraphvizMacro) 
     84        else: 
     85            return None 
    6986 
    7087 
     
    7390 
    7491        req - ? 
    75          
     92 
    7693        name - Wiki macro command that resulted in this method being 
    7794               called. In this case, it should be 'graphviz', followed 
     
    149166            return buf.getvalue() 
    150167 
    151         sha_key  = sha.new(self.processor + content).hexdigest() 
     168        encoding = 'utf-8' 
     169        if type(content) == type(u''): 
     170            content  = content.encode(encoding) 
     171            sha_text = self.processor.encode(encoding) + self.processor_options.encode(encoding) + content 
     172        else: 
     173            sha_text = self.processor + self.processor_options + content 
     174 
     175        sha_key  = sha.new(sha_text).hexdigest() 
    152176        img_name = '%s.%s.%s' % (sha_key, self.processor, self.out_format) # cache: hash.<dot>.<png> 
    153177        img_path = os.path.join(self.cache_dir, img_name) 
     
    224248                dimensions = 'width="100%" height="100%"' 
    225249            # insert SVG, IE compatibility 
    226             buf.write('<!--[if IE]><embed src="%s/%s" type="image/svg+xml" %s></embed><![endif]--> ' % (self.prefix_url, img_name, dimensions)) 
    227             buf.write('<![if !IE]><object data="%s/%s" type="image/svg+xml" %s>SVG Object</object><![endif]>' % (self.prefix_url, img_name, dimensions)) 
     250            buf.write('<!--[if IE]><embed src="%s/graphviz/%s" type="image/svg+xml" %s></embed><![endif]--> ' % (req.base_url, img_name, dimensions)) 
     251            buf.write('<![if !IE]><object data="%s/graphviz/%s" type="image/svg+xml" %s>SVG Object</object><![endif]>' % (req.base_url, img_name, dimensions)) 
    228252 
    229253        # for binary formats, add map 
     
    234258            map = "".join(map).replace('\n', '') 
    235259            buf.write('<map id="%s" name="%s">%s</map>' % (sha_key, sha_key, map)) 
    236             buf.write('<img id="%s" src="%s/%s" usemap="#%s" alt="GraphViz image"/>' % (sha_key, self.prefix_url, img_name, sha_key)) 
    237  
    238         else: 
    239             buf.write('<img src="%s/%s"/>' % (self.prefix_url, img_name)) 
     260            buf.write('<img id="%s" src="%s/graphviz/%s" usemap="#%s" alt="GraphViz image"/>' % (sha_key, req.base_url, img_name, sha_key)) 
     261 
     262        else: 
     263            buf.write('<img src="%s/graphviz/%s"/>' % (req.base_url, img_name)) 
    240264 
    241265        return buf.getvalue() 
     
    243267 
    244268    def expand_wiki_links(self, match): 
    245         #self.log.debug('expand_wiki_links.match.groups: %s' % str(match.groups())) 
    246          
    247269        wiki_url = match.groups()[0]                     # TracLink ([1], source:file/, ...) 
    248270        html_url = wiki_to_oneliner(wiki_url, self.env)  # <a href="http://someurl">...</a> 
    249271        href     = re.search('href="(.*?)"', html_url)   # http://someurl 
    250          
    251         url      = 'URL="%s"' % href.groups()[0] 
    252         #self.log.debug('expand_wiki_links.url: %(url)s' % locals()) 
    253  
    254         return url 
     272        url      = href and href.groups()[0] or html_url 
     273        if self.out_format == 'svg': 
     274            format = 'URL="javascript:window.parent.location.href=\'%s\'"' 
     275        else: 
     276            format = 'URL="%s"' 
     277        return format % url 
    255278 
    256279 
     
    281304                #self.log.debug('self.cache_dir: %s' % self.cache_dir) 
    282305 
     306 
     307            #Get optional configuration parameters from trac.ini. 
     308 
     309            # check for the default processor - processor 
     310            self.processor = self.config.get('graphviz', 'processor', GraphvizMacro.processors[0]) 
     311            #self.log.debug('self.processor: %s' % self.processor) 
     312 
    283313            # check for the cmd_path entry 
    284             self.cmd_path = self.config.get('graphviz', 'cmd_path') 
     314            self.cmd_path = None 
     315            if sys.platform in GraphvizMacro.cmd_paths: 
     316                self.cmd_path = GraphvizMacro.cmd_paths[sys.platform] 
     317            self.cmd_path = self.config.get('graphviz', 'cmd_path', self.cmd_path) 
    285318            if not self.cmd_path: 
    286                 msg = 'The <b>graphviz</b> section is missing the <b>cmd_path</b> field.' 
     319                msg = 'The <b>graphviz</b> section is missing the <b>cmd_path</b> field and there is no default for %s.' % sys.platform 
    287320                buf = self.show_err(msg) 
    288321                trouble = True 
     
    292325                trouble = True 
    293326 
     327                #self.log.debug('self.cmd_path: %s' % self.cmd_path) 
     328 
     329            else: 
     330                pname = os.path.join(self.cmd_path, self.processor) + self.exe_suffix 
     331                if not os.path.exists(pname): 
     332                    msg = 'The default processor, <b>%s</b>, was not found.' % pname 
     333                    buf = self.show_err(msg) 
     334                    trouble = True 
     335 
    294336                for name in GraphvizMacro.processors: 
    295337                    pname = os.path.join(self.cmd_path, name) + self.exe_suffix 
    296338                    if not os.path.exists(pname): 
    297                         msg = 'The <b>%s</b> program was not found.' % pname 
    298                         buf = self.show_err(msg) 
    299                         trouble = True 
    300  
    301                 #self.log.debug('self.cmd_path: %s' % self.cmd_path) 
    302  
    303             # check for the prefix_url entry 
    304             self.prefix_url = self.config.get('graphviz', 'prefix_url') 
    305             #self.log.debug('self.prefix_url: %s' % self.prefix_url) 
    306             if not self.prefix_url: 
    307                 msg = 'The <b>graphviz</b> section is missing the <b>prefix_url</b> field.' 
    308                 buf = self.show_err(msg) 
    309                 trouble = True 
    310  
    311  
    312             #Get optional configuration parameters from trac.ini. 
     339                        self.log.warn('The %s program was not found. The graphviz/%s macro will be disabled.' % (pname, name)) 
     340                        GraphvizMacro.processors.remove(name) 
    313341 
    314342            # check for the default output format - out_format 
     
    316344            #self.log.debug('self.out_format: %s' % self.out_format) 
    317345 
    318             # check for the default processor - processor 
    319             self.processor = self.config.get('graphviz', 'processor', GraphvizMacro.processors[0]) 
    320             #self.log.debug('self.processor: %s' % self.processor) 
    321  
    322346            # check if png anti aliasing should be done - png_antialias 
    323347            self.png_anti_alias = self.boolean(self.config.get('graphviz', 'png_antialias', False)) 
     
    325349 
    326350            if self.png_anti_alias == True: 
    327                 self.rsvg_path = self.config.get('graphviz', 'rsvg_path', '/usr/bin/rsvg'
     351                self.rsvg_path = self.config.get('graphviz', 'rsvg_path', os.path.join(self.cmd_path, 'rsvg')
    328352 
    329353                if not os.path.exists(self.rsvg_path): 
     
    364388            self.dpi = int(self.config.get('graphviz', 'default_graph_dpi', 96)) 
    365389 
     390        # setup mimetypes to support the IHTMLPreviewRenderer interface 
     391        if 'graphviz' not in MIME_MAP: 
     392            MIME_MAP['graphviz'] = 'application/graphviz' 
     393        for processor in GraphvizMacro.processors: 
     394            if processor not in MIME_MAP: 
     395                MIME_MAP[processor] = 'application/graphviz' 
     396 
    366397        return trouble, buf 
    367398 
     
    369400    def launch(self, cmd, input): 
    370401        """Launch a process (cmd), and returns exitcode, stdout + stderr""" 
    371        p_in, p_out, p_err = os.popen3(cmd) 
     402        p_in, p_out, p_err = os.popen3(cmd) 
    372403        if input: 
    373             p_in.writelines(input) 
     404            p_in.write(input) 
    374405        p_in.close() 
    375406        out = p_out.read() 
     
    384415                   <strong>Graphviz macro processor has detected an error. Please fix the problem before continuing.</strong> \n\ 
    385416                   <pre>%s</pre> \n\ 
    386                    </div></div>' % msg
     417                   </div></div>' % escape(msg)
    387418        self.log.error(msg) 
    388419        return buf 
     
    451482 
    452483 
    453     # IRequestHandler methods 
    454     def match_request(self, req): 
    455         return req.path_info.startswith('/graphviz') 
    456      
    457  
    458     def process_request(self, req): 
    459         pieces = [item for item in req.path_info.split('/graphviz') if len(item)] 
    460         self.log.debug('process_request:pieces %s' % str(pieces)) 
    461  
    462         trouble, msg = self.load_config() 
    463         if trouble: 
    464             return msg.getvalue() 
    465  
    466         img_path = os.path.join(self.cache_dir, pieces[0]) 
    467  
    468         if os.path.exists(img_path): 
    469             req.send_file(img_path) 
    470  
    471         self.log.warning('File %s not found', img_path) 
    472         raise HTTPNotFound('File %s not found', img_path) 
    473  
    474  
    475484    # Extra helper functions 
    476485    def boolean(self, value): 
     
    479488            value = value.lower() in _TRUE_VALUES 
    480489        return bool(value) 
     490 
     491 
     492    MIME_TYPES = ('application/graphviz') 
     493 
     494    # IHTMLPreviewRenderer methods 
     495 
     496    def get_quality_ratio(self, mimetype): 
     497        self.log.error(mimetype) 
     498        if mimetype in self.MIME_TYPES: 
     499            return 2 
     500        return 0 
     501 
     502    def render(self, req, mimetype, content, filename=None, url=None): 
     503        ext = filename.split('.')[1] 
     504        name = ext == 'graphviz' and 'graphviz' or 'graphviz.%s' % ext 
     505        text = hasattr(content, 'read') and content.read() or content 
     506        return self.render_macro(req, name, text) 
     507 
     508 
     509    # IRequestHandler methods 
     510    def match_request(self, req): 
     511        return req.path_info.startswith('/graphviz') 
     512 
     513 
     514    def process_request(self, req): 
     515        # check and load the configuration 
     516        trouble, msg = self.load_config() 
     517        if trouble: 
     518            return msg.getvalue() 
     519 
     520        pieces = [item for item in req.path_info.split('/graphviz') if len(item)] 
     521 
     522        if len(pieces): 
     523            pieces = [item for item in pieces[0].split('/') if len(item)] 
     524 
     525            if len(pieces): 
     526                name = pieces[0] 
     527                img_path = os.path.join(self.cache_dir, name) 
     528                return req.send_file(img_path) 
     529        return 
  • graphvizplugin/branches/v0.7/graphviz/__init__.py

    r548 r1601  
    33$HeadURL$ 
    44 
    5 Copyright (c) 2005 Peter Kropf. All rights reserved. 
     5Copyright (c) 2005, 2006 Peter Kropf. All rights reserved. 
    66 
    77Module file for the graphviz trac wiki processor. 
  • graphvizplugin/branches/v0.7/README.txt

    r721 r1601  
    5151#!graphviz.dot/png 
    5252#!graphviz.circo/gif 
     53 
     54 
     55Platform Specific Requirements 
     56============================== 
     57 
     58FreeBSD 
     59+++++++ 
     60 
     61On FreeBSD systems, installing the x11-fonts/urwfonts package will 
     62provide the fonts needed for graphviz to correctly generate images. 
    5363 
    5464 
     
    105115                      generated images. 
    106116 
    107     prefix_url      - The url to be used to find the cached images. This 
    108                       must point to the trac server's view of the 
    109                       cache_dir location. 
    110  
    111117    cmd_path        - Full path to the directory where the graphviz 
    112                       programs are located. 
     118                      programs are located. If not specified, the 
     119                      default is /usr/bin on Linux, c:\Program 
     120                      Files\ATT\Graphviz\bin on Windows and 
     121                      /usr/local/bin on FreeBSD 6. 
    113122 
    114123    out_format      - Graph output format. Valid formats are: png, jpg, 
     
    117126                      basis. 
    118127 
    119     processor       - Graphviz default processor. Valid processors are: 
    120                       dot, neato, twopi, fdp, circo. If not specified, 
    121                       the default is dot. This setting can be overrided 
    122                       on a per-graph basis. 
     128    processor       - Graphviz default processor. Valid processors 
     129                      are: dot, neato, twopi, fdp, circo. If not 
     130                      specified, the default is dot. This setting can 
     131                      be overrided on a per-graph basis. 
     132 
     133                      GraphvizMacro will verify that the default 
     134                      processor is installed and will not work if it 
     135                      is missing. All other processors are optional. 
     136                      If any of the other processors are missing, a 
     137                      warning message will be sent to the trac log and 
     138                      GraphvizMacro will continue to work. 
    123139 
    124140    png_antialias   - If this entry exists in the configuration file, 
    125                       then PNG outputs will be antialiased and the 
    126                       rsvg_path must be defined. 
     141                      then PNG outputs will be antialiased. 
    127142 
    128143    rsvg_path       - Full path to where the rsvg binary can be found. 
     144                      The default is cmd_path + rsvg. 
    129145 
    130146    default_*       - These settings define the default graph, node and 
     
    154170                      contain. This is the high watermark for the 
    155171                      directory entry count. 
    156  
    157 The cache_dir and prefix_url entries are related to each other. The 
    158 cache_dir entry points to a location on the file system and the 
    159 prefix_url points to the same location but from the trac server's 
    160 point of view. This allows the graphviz programs to generate the 
    161 images and the user's web browser to view them. 
    162172 
    163173The cache_dir directory must exist and the trac server must have read 
     
    182192[graphviz] 
    183193cache_dir = /tmp/trac/htdocs/graphviz 
    184 prefix_url = http://localhost:8000/trac/chrome/site/graphviz 
    185 cmd_path = /usr/bin 
    186 out_format = png 
    187194png_antialias = true 
    188 rsvg_path = /usr/bin/rsvg 
    189195default_graph_fontname = "Andale Mono" 
    190196default_graph_fontsize = 10 
     
    195201[graphviz] 
    196202cache_dir = /tmp/trac/htdocs/graphviz 
    197 prefix_url = http://localhost:8000/trac/chrome/site/graphviz 
    198 cmd_path = /usr/bin 
    199 out_format = png 
    200203png_antialias = true 
    201 rsvg_path = /usr/bin/rsvg 
    202204default_graph_fontname = "Andale Mono" 
    203205default_graph_fontsize = 10 
     
    222224[graphviz] 
    223225cache_dir = C:\projects\plugins\env\trac\htdocs\graphviz 
    224 prefix_url = http://localhost:8080/trac/chrome/site/graphviz 
    225 cmd_path = c:\Program Files\ATT\Graphviz\bin 
    226 out_format = png 
    227226cache_manager = yes 
    228227cache_max_size = 10000000 
  • graphvizplugin/branches/v0.7/ReleaseNotes.txt

    r1600 r1601  
    11Trac Graphviz Plugin v0.7.0 Release Notes 
    22========================================= 
    3 June 1, 2006 
     3November 25, 2006 
    44 
    55Graphviz plugin v0.7.0 for Trac is now available. The Graphviz wiki 
     
    1515 
    1616 
     17Changes for release v0.6.8 
     18-------------------------- 
     19 
     20* Added better support for non-ascii characters in graphviz wiki 
     21  documents. 
     22 
     23 
     24Changes for release v0.6.7 
     25-------------------------- 
     26 
     27* The GraphvizMacro v0.6.5 release introduced a bug with the now 
     28  optional cmd_path. If run on a platform whose sys.platform name is 
     29  not in the GraphvizMacro.cmd_paths dictionary, the self.cmd_path 
     30  variable isn't initialized. This caused a wee problem and stack 
     31  trace in Trac. 
     32 
     33 
     34Changes for release v0.6.6 
     35-------------------------- 
     36 
     37* The GraphvizMacro v0.6.5 release introduced a bug with the 
     38  IHTMLPreviewRenderer interface. The render method assumed that the 
     39  content parameter was an object with a read method. Under trac 0.10 
     40  with a Subversion repository, this object is a svn.core.Stream. 
     41  Under trac 0.9 the object is a string with the contents from the 
     42  repository. As a result, the v0.6.5 wouldn't render the images and 
     43  the raw text was displayed. 
     44 
     45 
     46Changes for release v0.6.5 
     47-------------------------- 
     48 
     49* The default graphviz processor is now the only processor that must 
     50  be found on the system. GraphvizMacro will not work without it. If 
     51  any of the other processors are missing, a warning message will be 
     52  sent to the trac log, the processor will be removed from the list of 
     53  known GraphvizMacro processors and GraphvizMacro will continue. 
     54  Resolves issue http://trac-hacks.org/ticket/159. 
     55 
     56* The cmd_path configuration parameter in trac.ini is now 
     57  optional. Reasonable default values have been set for Linux, Win32 
     58  and FreeBSD6. 
     59 
     60* Altered the way the GraphvizMacro description is returned in 
     61  get_macro_description. Instead of returning a description for each 
     62  variant (graphviz, graphviz/png, graphviz/svg, etc.) only return a 
     63  description for graphviz. This will cleanup the WikiMacros page a 
     64  bit to hopefully make it easier to navigate. It isn't a perfect 
     65  solution since all the graphviz macro names are still displayed but 
     66  it no longer repeats the same description for each 
     67  permutation. Resolves issue http://trac-hacks.org/ticket/284. 
     68 
     69* Implemented the IRequestHandler interface to return graphviz 
     70  generated images. This means that graphviz images can be referenced 
     71  via http://URL_TO_TRAC_SERVER/graphviz/HASH_KEY. As a result of this 
     72  change, the prefix_url configuration parameter is no longer needed 
     73  in the trac.ini file. Resolves issue 
     74  http://trac-hacks.org/ticket/86. 
     75 
     76* Links within images that are rendered as SVG are now automatically 
     77  prefixed with javascript:window.parent.location.href= to force the 
     78  link to be displayed in the parent window instead of the SVG object 
     79  window. Resolves issue http://trac-hacks.org/ticket/560. 
     80 
     81* Included the processor options when calculating the sha key used for 
     82  the image file name. This should help in testing various graphviz 
     83  settings in trac.ini. Resolves issue 
     84  http://trac-hacks.org/ticket/575. 
     85 
     86* Fixed expand_wiki_links to allow for javascript URL 
     87  references. Resolves issue http://trac-hacks.org/ticket/559. 
     88 
     89* GraphvizMacro is now also an IHTMLPreviewRenderer. This was done by 
     90  adding application/graphviz as the mimetype for files with the 
     91  extension of .graphviz, .dot, .neato, .twopi, .circo and .fdp. When 
     92  browsing the source code in the respoitory, any files with those 
     93  extensions will be treated as graphviz programs and will be rendered 
     94  via the GraphvizMacro. Resolves issue 
     95  http://trac-hacks.org/attachment/ticket/576. 
     96 
     97* Escaped the error message before displaying it. Resolves issue 
     98  http://trac-hacks.org/ticket/574. 
     99 
     100 
    17101Changes for release v0.6.4 
    18102-------------------------- 
  • graphvizplugin/branches/v0.7/setup.py

    r1600 r1601  
    3333text of a wiki page can contain the source text for graphviz and the 
    3434web browser will show the resulting image.""", 
    35     license = """Copyright (C) 2005,2006 Peter Kropf 
     35    license = """Copyright (C) 2005, 2006 Peter Kropf 
    3636All rights reserved. 
    3737