1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
import os, sys, re
import msgstruct
this_dir = os.path.dirname(os.path.abspath(__file__))
GRAPHSERVER = os.path.join(this_dir, 'graphserver.py')
def display_dot_file(dotfile, wait=True, save_tmp_file=None):
""" Display the given dot file in a subprocess.
"""
if not os.path.exists(str(dotfile)):
raise IOError("No such file: %s" % (dotfile,))
import graphpage
page = graphpage.DotFileGraphPage(str(dotfile))
display_page(page, wait=wait, save_tmp_file=save_tmp_file)
def display_page(page, wait=True, save_tmp_file=None):
messages = [(msgstruct.CMSG_INIT, msgstruct.MAGIC)]
history = [page]
pagecache = {}
def getpage(graph_id):
page = history[graph_id]
try:
return pagecache[page]
except KeyError:
result = page.content()
pagecache.clear() # a cache of a single entry should be enough
pagecache[page] = result
return result
def reload(graph_id):
page = getpage(graph_id)
if save_tmp_file:
f = open(save_tmp_file, 'w')
f.write(page.source)
f.close()
messages.extend(page_messages(page, graph_id))
send_graph_messages(io, messages)
del messages[:]
io = spawn_handler()
reload(0)
if wait:
try:
while True:
msg = io.recvmsg()
# handle server-side messages
if msg[0] == msgstruct.MSG_RELOAD:
graph_id = msg[1]
pagecache.clear()
reload(graph_id)
elif msg[0] == msgstruct.MSG_FOLLOW_LINK:
graph_id = msg[1]
word = msg[2]
page = getpage(graph_id)
try:
page = page.followlink(word)
except KeyError:
io.sendmsg(msgstruct.CMSG_MISSING_LINK)
else:
# when following a link from an older page, assume that
# we can drop the more recent history
graph_id += 1
history[graph_id:] = [page]
reload(graph_id)
except EOFError:
pass
except Exception, e:
send_error(io, e)
raise
io.close()
def page_messages(page, graph_id):
import graphparse
return graphparse.parse_dot(graph_id, page.source, page.links,
getattr(page, 'fixedfont', False))
def send_graph_messages(io, messages):
ioerror = None
for msg in messages:
try:
io.sendmsg(*msg)
except IOError, ioerror:
break
# wait for MSG_OK or MSG_ERROR
try:
while True:
msg = io.recvmsg()
if msg[0] == msgstruct.MSG_OK:
break
except EOFError:
ioerror = ioerror or IOError("connexion unexpectedly closed "
"(graphserver crash?)")
if ioerror is not None:
raise ioerror
def send_error(io, e):
try:
errmsg = str(e)
if errmsg:
errmsg = '%s: %s' % (e.__class__.__name__, errmsg)
else:
errmsg = '%s' % (e.__class__.__name__,)
io.sendmsg(msgstruct.CMSG_SAY, errmsg)
except Exception:
pass
def spawn_handler():
gsvar = os.environ.get('GRAPHSERVER')
if not gsvar:
try:
return spawn_sshgraphserver_handler()
except Exception, e:
return spawn_local_handler()
else:
try:
host, port = gsvar.split(':')
host = host or '127.0.0.1'
port = int(port)
except ValueError:
raise ValueError("$GRAPHSERVER must be set to HOST:PORT, got %r" %
(gvvar,))
return spawn_graphserver_handler((host, port))
def spawn_local_handler():
if hasattr(sys, 'pypy_objspaceclass'):
python = 'python'
else:
python = sys.executable
cmdline = '"%s" -u "%s" --stdio' % (python, GRAPHSERVER)
child_in, child_out = os.popen2(cmdline, 'tb')
io = msgstruct.FileIO(child_out, child_in)
return io
def spawn_graphserver_handler(address):
import socket
s = socket.socket()
s.connect(address)
return msgstruct.SocketIO(s)
def spawn_sshgraphserver_handler():
import tempfile, getpass
tmpdir = tempfile.gettempdir()
user = getpass.getuser()
fn = os.path.join(tmpdir, 'dotviewer-sshgraphsrv-%s' % user)
f = open(fn, 'r')
port = int(f.readline().rstrip())
f.close()
return spawn_graphserver_handler(('127.0.0.1', port))
|