importos,sys,reimportsubprocessimportmsgstructthis_dir=os.path.dirname(os.path.abspath(__file__))GRAPHSERVER=os.path.join(this_dir,'graphserver.py')defdisplay_dot_file(dotfile,wait=True,save_tmp_file=None):""" Display the given dot file in a subprocess. """ifnotos.path.exists(str(dotfile)):raiseIOError("No such file: %s"%(dotfile,))importgraphpagepage=graphpage.DotFileGraphPage(str(dotfile))display_page(page,wait=wait,save_tmp_file=save_tmp_file)defdisplay_page(page,wait=True,save_tmp_file=None):messages=[(msgstruct.CMSG_INIT,msgstruct.MAGIC)]history=[page]pagecache={}defgetpage(graph_id):page=history[graph_id]try:returnpagecache[page]exceptKeyError:result=page.content()pagecache.clear()# a cache of a single entry should be enoughpagecache[page]=resultreturnresultdefreload(graph_id):page=getpage(graph_id)ifsave_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)delmessages[:]io=spawn_handler()reload(0)ifwait:try:whileTrue:msg=io.recvmsg()# handle server-side messagesifmsg[0]==msgstruct.MSG_RELOAD:graph_id=msg[1]pagecache.clear()reload(graph_id)elifmsg[0]==msgstruct.MSG_FOLLOW_LINK:graph_id=msg[1]word=msg[2]page=getpage(graph_id)try:page=page.followlink(word)exceptKeyError:io.sendmsg(msgstruct.CMSG_MISSING_LINK)else:# when following a link from an older page, assume that# we can drop the more recent historygraph_id+=1history[graph_id:]=[page]reload(graph_id)exceptEOFError:passexceptException,e:send_error(io,e)raiseio.close()defpage_messages(page,graph_id):importgraphparsereturngraphparse.parse_dot(graph_id,page.source,page.links,getattr(page,'fixedfont',False))defsend_graph_messages(io,messages):ioerror=Noneformsginmessages:try:io.sendmsg(*msg)exceptIOError,ioerror:break# wait for MSG_OK or MSG_ERRORtry:whileTrue:msg=io.recvmsg()ifmsg[0]==msgstruct.MSG_OK:breakexceptEOFError:ioerror=ioerrororIOError("connection unexpectedly closed ""(graphserver crash?)")ifioerrorisnotNone:raiseioerrordefsend_error(io,e):try:errmsg=str(e)iferrmsg:errmsg='%s: %s'%(e.__class__.__name__,errmsg)else:errmsg='%s'%(e.__class__.__name__,)io.sendmsg(msgstruct.CMSG_SAY,errmsg)exceptException:passdefspawn_handler():gsvar=os.environ.get('GRAPHSERVER')# deprecatedifnotgsvar:try:returnspawn_sshgraphserver_handler()exceptException,e:returnspawn_local_handler()else:try:host,port=gsvar.split(':')host=hostor'127.0.0.1'port=int(port)exceptValueError:raiseValueError("$GRAPHSERVER must be set to HOST:PORT, got %r"%(gvvar,))returnspawn_graphserver_handler((host,port))defspawn_local_handler():ifhasattr(sys,'pypy_objspaceclass'):python='/usr/bin/python'else:python=sys.executableargs=[python,'-u',GRAPHSERVER,'--stdio']p=subprocess.Popen(args,stdout=subprocess.PIPE,stdin=subprocess.PIPE)child_in,child_out=p.stdin,p.stdoutio=msgstruct.FileIO(child_out,child_in)returniodefspawn_graphserver_handler(address):importsockets=socket.socket()s.connect(address)returnmsgstruct.SocketIO(s)defspawn_sshgraphserver_handler():importtempfile,getpasstmpdir=tempfile.gettempdir()user=getpass.getuser()fn=os.path.join(tmpdir,'dotviewer-sshgraphsrv-%s'%user)st=os.stat(fn)ifst.st_uid!=os.getuid():raiseOSError("wrong owner on "+fn)f=open(fn,'r')port=int(f.readline().rstrip())f.close()returnspawn_graphserver_handler(('127.0.0.1',port))