Source

trac-ticketlinks / contrib / workflow / workflow_parser.py

Full commit
ecarter a6c1494 



ecarter cb14bf7 
nkantrowitz f9b20a7 



ecarter a6c1494 
ecarter 2b3e4d4 
ecarter a6c1494 
cboos 2c41609 
ecarter a6c1494 



































cboos 2c41609 






ecarter a6c1494 





ecarter 13abd5e 

ecarter a6c1494 


cboos 2c41609 
ecarter a6c1494 

cboos 2c41609 
ecarter a6c1494 

ecarter cb14bf7 
ecarter a6c1494 









ecarter cb14bf7 
ecarter a6c1494 

ecarter cb14bf7 
ecarter a6c1494 




























ecarter cb14bf7 





#!/usr/bin/env python

import sys
import getopt
import locale

import pkg_resources
pkg_resources.require('Trac')

from trac.config import Configuration
from trac.ticket.default_workflow import parse_workflow_config

_debug = False
def debug(s):
    if _debug:
        sys.stderr.write(s)

def readconfig(filename):
    """Returns a list of raw config options"""
    config = Configuration(filename)
    rawactions = list(config.options('ticket-workflow'))
    debug("%s\n" % str(rawactions))
    if not rawactions:
        sys.stderr.write("ERROR: You don't seem to have a [ticket-workflow] "
                         "section.\n")
        sys.exit(1)
    return rawactions

class ColorScheme(object):
    # cyan, yellow are too light in color
    colors = ['black', 'blue', 'red', 'green', 'purple', 'orange', 'darkgreen']
    def __init__(self):
        self.mapping = {}
        self.coloruse = [0,] * len(self.colors)
    def get_color(self, name):
        try:
            colornum = self.mapping[name]
        except(KeyError):
            self.mapping[name] = colornum = self.pick_color(name)
        self.coloruse[colornum] += 1
        return self.colors[colornum]
    def pick_color(self, name):
        """Pick a color that has not been used much so far."""
        return self.coloruse.index(min(self.coloruse))

def actions2graphviz(actions, show_ops=False, show_perms=False):
    """Returns a list of lines to be fed to graphviz."""
    # The size value makes it easier to create a useful printout.
    color_scheme = ColorScheme()
    digraph_lines = ["""
digraph G {
  center=1
  size="10,8"
  { rank=source; new [ shape=invtrapezium ] }
  { rank=sink; closed [ shape=trapezium ] }
    """]
    for action, attributes in actions.items():
        label = [attributes['name'], ]
        if show_ops:
            label += attributes['operations']
        if show_perms:
            label += attributes['permissions']
        if 'set_resolution' in attributes:
            label += ['(' + attributes['set_resolution'] + ')'] 
        for oldstate in attributes['oldstates']:
            color = color_scheme.get_color(attributes['name'])
            digraph_lines.append(
                '  "%s" -> "%s" [label="%s" color=%s fontcolor=%s]' % \
                (oldstate, attributes['newstate'], '\\n'.join(label), color,
                 color))
    digraph_lines.append('}')
    return digraph_lines

def main(filename, output, show_ops=False, show_perms=False):
    # Read in the config
    rawactions = readconfig(filename)

    # Parse the config information
    actions = parse_workflow_config(rawactions)

    # Convert to graphviz
    digraph_lines = actions2graphviz(actions, show_ops, show_perms)

    # And output
    output.write(unicode.encode('\n'.join(digraph_lines), locale.getpreferredencoding()))

def usage(output):
    output.write('workflow_parser [options] configfile.ini [output.dot]\n'
                 '-h --help shows this message\n'
                 '-o --operations include operations in the graph\n'
                 '-p --permissions include permissions in the graph\n'
    )

if __name__ == '__main__':
    show_ops = False
    show_perms = False
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'hop', ['help', 'operations',
                                                         'permissions'])
    except getopt.GetoptError:
        usage(sys.stderr)
        sys.exit(1)

    for option, argument in opts:
        if option in ('-h', '--help'):
            usage(sys.stdout)
            sys.exit(0)
        elif option in ('-o', '--operations'):
            show_ops = True
        elif option in ('-p', '--permissions'):
            show_perms = True
            
    if not args:
        sys.stderr.write('Syntax error: config filename required.\n')
        usage(sys.stderr)
        sys.stderr.flush()
        sys.exit(1)
    ini_filename = args[0]
    if len(args) > 1:
        output = open(args[1], 'w')
    else:
        output = sys.stdout

    main(ini_filename, output, show_ops, show_perms)