1. Yuya Nishihara
  2. hgext-workarounds

Commits

Yuya Nishihara  committed 08a7c67

thgbackdoor: extract BackDoorServer class to reduce monky-patches

  • Participants
  • Parent commits e99d961
  • Branches default

Comments (0)

Files changed (1)

File hgext/thgbackdoor.py

View file
 http://stackoverflow.com/questions/2749655/
 """
 import os, traceback
-from PyQt4.QtCore import QByteArray, QObject, QTimer, Qt, pyqtSlot
+from PyQt4.QtCore import QByteArray, QObject, QTimer, Qt, pyqtSignal, pyqtSlot
 from PyQt4.QtNetwork import QHostAddress, QLocalServer, QTcpServer
 from mercurial import demandimport
 
         except Exception:  # avoid multiple exception
             pass
 
+class BackDoorServer(QObject):
+    """Manages TCP/Local server and established session"""
+    _excinfogot = pyqtSignal(object, object, object)
+
+    def __init__(self, ui, parent=None):
+        super(BackDoorServer, self).__init__(parent)
+        self._ui = ui
+        self._context = {}
+        self._sock = None  # should be assigned later
+
+    def updatecontext(self, context):
+        self._context.update(context)
+
+    def listen(self, address):
+        """Start listening at the specified address"""
+        if self._sock:
+            raise ValueError('already listening')
+        if ':' in address:
+            self._setuptcpserver(address)
+        elif address:
+            self._setuplocalserver(address)
+
+    def _setuptcpserver(self, address):
+        host, port = address.split(':', 1)
+        if host == 'localhost':
+            host = '127.0.0.1'
+        port = int(port)
+        self._sock = sock = QTcpServer(self)
+        sock.newConnection.connect(self._handleconnection)
+        if sock.listen(QHostAddress(host), port):
+            self._ui.note('thgbackdoor: listening at %s:%d\n'
+                          % (sock.serverAddress().toString(),
+                             sock.serverPort()))
+        else:
+            self._ui.warn('thgbackdoor: failed to listen at %s:%d\n'
+                          % (host, port))
+
+    def _setuplocalserver(self, address):
+        QLocalServer.removeServer(address)
+        self._sock = sock = QLocalServer(self)
+        sock.newConnection.connect(self._handleconnection)
+        if sock.listen(address):
+            self._ui.note('thgbackdoor: listening at %s\n'
+                          % sock.fullServerName())
+        else:
+            self._ui.warn('thgbackdoor: failed to listen at %s\n' % address)
+
+    @pyqtSlot()
+    def _handleconnection(self):
+        while self._sock.hasPendingConnections():
+            self._ui.note('thgbackdoor: new connection\n')
+            conn = self._sock.nextPendingConnection()
+            session = BackDoorSession(self._context, conn, parent=self)
+            self._excinfogot.connect(session.dumpexcinfo)
+            conn.disconnected.connect(session.deleteLater)
+
+    def close(self):
+        self._context.clear()
+        if self._sock:
+            self._sock.close()
+            self._sock.deleteLater()
+            self._sock = None
+
+    @pyqtSlot(object, object, object)
+    def notifyexcinfo(self, etype, evalue, traceback):
+        self._excinfogot.emit(etype, evalue, traceback)
+
 def wrapqtrun(ui, qtrun):
     class BackDoorQtRunner(qtrun.__class__):
-        # work around thg's stderr hack
-        _lui = ui.copy()
-        _lui.ferr = os.fdopen(2, 'w')
-
-        _backdoorcontext = {}
-        _backdoorsock = None  # should be assigned later
-
-        @pyqtSlot()
-        def _handlebackdoorconnection(self):
-            while self._backdoorsock.hasPendingConnections():
-                self._lui.note('thgbackdoor: new connection\n')
-                sock = self._backdoorsock.nextPendingConnection()
-                session = BackDoorSession(self._backdoorcontext, sock,
-                                          parent=self)
-                self._exceptionOccured.connect(session.dumpexcinfo,
-                                               Qt.QueuedConnection)
-                sock.disconnected.connect(session.deleteLater)
-
-        def _setupbackdoortcpserver(self, address):
-            host, port = address.split(':', 1)
-            if host == 'localhost':
-                host = '127.0.0.1'
-            port = int(port)
-            self._backdoorsock = sock = QTcpServer(self)
-            sock.newConnection.connect(self._handlebackdoorconnection)
-            if sock.listen(QHostAddress(host), port):
-                self._lui.note('thgbackdoor: listening at %s:%d\n'
-                               % (sock.serverAddress().toString(),
-                                  sock.serverPort()))
-            else:
-                self._lui.warn('thgbackdoor: failed to listen at %s:%d\n'
-                               % (host, port))
-
-        def _setupbackdoorlocalserver(self, address):
-            QLocalServer.removeServer(address)
-            self._backdoorsock = sock = QLocalServer(self)
-            sock.newConnection.connect(self._handlebackdoorconnection)
-            if sock.listen(address):
-                self._lui.note('thgbackdoor: listening at %s\n'
-                               % sock.fullServerName())
-            else:
-                self._lui.warn('thgbackdoor: failed to listen at %s\n'
-                               % address)
-
         def __call__(self, dlgfunc, ui, *args, **opts):
-            self._backdoorcontext.update(vars(run))
-            self._backdoorcontext.update(locals())
+            self._backdoorserver.updatecontext(vars(run))
+            self._backdoorserver.updatecontext(locals())
 
             def xdlgfunc(ui, *args, **opts):
                 # TODO use command-line option instead?
                 address = os.environ.get('THGBACKDOOR') or ''
-                if ':' in address:
-                    self._setupbackdoortcpserver(address)
-                elif address:
-                    self._setupbackdoorlocalserver(address)
+                self._backdoorserver.listen(address)
                 dlg = dlgfunc(ui, *args, **opts)
-                self._backdoorcontext['dlg'] = dlg
+                self._backdoorserver.updatecontext({'dlg': dlg})
                 return dlg
             xdlgfunc.func_name = dlgfunc.func_name
 
                 return super(BackDoorQtRunner, self).__call__(
                     xdlgfunc, ui, *args, **opts)
             finally:
-                self._backdoorcontext.clear()
-                if self._backdoorsock:
-                    self._backdoorsock.close()
+                self._backdoorserver.close()
 
     qtrun.__class__ = BackDoorQtRunner
 
+    # work around thg's stderr hack
+    lui = ui.copy()
+    lui.ferr = os.fdopen(2, 'w')
+    qtrun._backdoorserver = server = BackDoorServer(lui, parent=qtrun)
+    qtrun._exceptionOccured.connect(server.notifyexcinfo, Qt.QueuedConnection)
+
 def uisetup(ui):
     if not _runavail:
         return  # not a thg