~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to dotgraph.py

  • Committer: Aaron Bentley
  • Date: 2005-08-30 15:08:40 UTC
  • Revision ID: abentley@panoramicfeedback.com-20050830150840-8936a9619c581731
Renamed pastegraph to dotgraph, stripped non-dot functionality

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/env python2.4
2
 
import sys
3
2
from subprocess import Popen, PIPE
4
 
import cgi
5
 
import cgitb; cgitb.enable()
6
3
from urllib import urlencode
7
4
from xml.sax.saxutils import escape
8
5
import os.path
22
19
    def __str__(self):
23
20
        return self.name
24
21
 
25
 
def save_request(req):
26
 
    files = [int(f) for f in os.listdir(REQ_DIR)]
27
 
    files.sort()
28
 
    if len(files) == 0:
29
 
        stem = '0' 
30
 
    else:
31
 
        stem = str(files[-1]+1)
32
 
    filename = os.path.join(REQ_DIR, stem)
33
 
    file(filename, 'wb').write(req)
34
 
    return stem
35
 
 
36
 
 
37
 
def load_request(num):
38
 
    return file(os.path.join(REQ_DIR, num), 'rb').read()
39
 
 
40
 
 
41
 
def parsed_link(link):
42
 
    suffixes = {'$': "#ffee99",
43
 
                '!': "#ff0000",
44
 
                '\'': "#eeeeee",
45
 
                '?': "#7799ff",
46
 
    }
47
 
    if link[-1] in suffixes:
48
 
        return link[:-1], suffixes[link[-1]]
49
 
    else:
50
 
        return link, None
51
 
 
52
 
def parse(input):
53
 
    input = input.replace('\n', ' ')
54
 
    input = input.replace('\r', ' ')
55
 
    statements = input.split(' ')
56
 
    relations = []
57
 
    nodes = {}
58
 
    for statement in statements:
59
 
        if len(statement.strip(' ')) == 0:
60
 
            continue
61
 
        links = statement.split('->')
62
 
        new_links = []
63
 
        for link, color in (parsed_link(l) for l in links):
64
 
            if link not in nodes:
65
 
                nodes[link] = Node(link, color)
66
 
            elif color is not None:
67
 
                nodes[link].color = color
68
 
            new_links.append(link)
69
 
        for i in range(len(links)-1):
70
 
            relations.append((nodes[new_links[i]], nodes[new_links[i+1]]))
71
 
    return relations
72
 
 
73
22
def dot_output(my_file, relations):
74
23
    defined = set()
75
24
    yield "digraph G\n"
98
47
        dot_proc.stdin.write(line)
99
48
    dot_proc.stdin.close()
100
49
    return dot_proc.wait()
101
 
 
102
 
def do_form(seqnum):
103
 
    if seqnum is not None:
104
 
        input = load_request(seqnum)
105
 
    else:
106
 
        input = "A->B B->C  A->C$"
107
 
    print "Content-type: text/html;charset=utf-8"
108
 
    print ""
109
 
    if input is not None:
110
 
        img_src = "?" + urlencode({"graphtext": input, "type": "img"})
111
 
        img = '<img src="%s" alt="result graph"/>' % escape(img_src)
112
 
    dotcode = ''.join(list(dot_output(sys.stdout, parse(input))))
113
 
    print """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/2002/REC-xhtml1-20020801/DTD/xhtml1-strict.dtd">
114
 
<html>
115
 
<head>
116
 
<title>Pastegraph</title>
117
 
</head>
118
 
<body>
119
 
    <p>
120
 
    This is a quikie tool for directed acyclic graphs.
121
 
    It uses a simple 'A->B' notation to describe the graphs.
122
 
    </p>
123
 
    <p>
124
 
       You can use the suffixes !, ', $ and ? to emphasize nodes.  E.g. A$->B
125
 
       will cause A to be yellow.
126
 
    </p>
127
 
    <p>
128
 
    Yes, that's Dot under the covers.
129
 
    </p>
130
 
    <form method="post" action="">
131
 
        <p><textarea name="graphtext" rows="5" cols="40">%s</textarea></p>
132
 
        <p><input type="submit" value="Draw graph"/></p>
133
 
        <p><input type="hidden" name="type" value="save"/></p>
134
 
    </form>
135
 
<div>%s</div>
136
 
<pre>%s</pre>
137
 
</body>
138
 
</html>""" % (input, img, escape(dotcode))
139
 
 
140
 
def save_redirect(input):
141
 
    seqnum = save_request(input)
142
 
    print "Status: 302 Found"
143
 
    print "Location: ?%s" %  urlencode({"n": seqnum})
144
 
 
145
 
 
146
 
def main():
147
 
    form = cgi.FieldStorage()
148
 
    type = form.getfirst("type", "form")
149
 
    input = form.getfirst("graphtext", "A->B B->C  A->C$")
150
 
    seqnum = form.getfirst("n", None)
151
 
    if type == "form":
152
 
        do_form(seqnum)
153
 
    elif type == "save":
154
 
        save_redirect(input)
155
 
    else:
156
 
      print "Content-type: image/gif\n"
157
 
      sys.stdout.flush()
158
 
      invoke_dot(dot_output(sys.stdout, parse(input)))
159
 
main()