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 152 153 154 155 156 157
|
import os, sys, re
import subprocess
import msgstruct
from strunicode import forcestr
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(forcestr(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, forcestr(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("connection 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') # deprecated
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():
python = os.getenv('PYPY_PYGAME_PYTHON')
if not python:
python = sys.executable
args = [python, '-u', GRAPHSERVER, '--stdio']
p = subprocess.Popen(args,
stdout=subprocess.PIPE, stdin=subprocess.PIPE)
child_in, child_out = p.stdin, p.stdout
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)
st = os.stat(fn)
if st.st_uid != os.getuid():
raise OSError("wrong owner on " + fn)
f = open(fn, 'r')
port = int(f.readline().rstrip())
f.close()
return spawn_graphserver_handler(('127.0.0.1', port))
|