Debugger eric7

Wed, 23 Nov 2022 10:48:46 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 23 Nov 2022 10:48:46 +0100
branch
eric7
changeset 9521
a663a8be64da
parent 9520
e12589f1d408
child 9522
f46abb15aab2

Debugger
- increased the configuration possibilities for the network interface the debug server listens on
- added the capability to configure the debug server of the IDE to listen at a fixed network port (default 35000)

docs/changelog.md file | annotate | diff | comparison | revisions
src/eric7/Debugger/DebugServer.py file | annotate | diff | comparison | revisions
src/eric7/EricNetwork/EricJsonServer.py file | annotate | diff | comparison | revisions
src/eric7/EricNetwork/EricJsonStreamReader.py file | annotate | diff | comparison | revisions
src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.py file | annotate | diff | comparison | revisions
src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.ui file | annotate | diff | comparison | revisions
src/eric7/Utilities/BackgroundService.py file | annotate | diff | comparison | revisions
diff -r e12589f1d408 -r a663a8be64da docs/changelog.md
--- a/docs/changelog.md	Tue Nov 22 16:33:30 2022 +0100
+++ b/docs/changelog.md	Wed Nov 23 10:48:46 2022 +0100
@@ -10,6 +10,11 @@
       utility
 - CycloneDX Interface
     - addad capability to generate readable (prettified) output
+- Debugger
+    - increased the configuration possibilities for the network interface the debug
+      server listens on
+    - added the capability to configure the debug server of the IDE to listen at a
+      fixed network port (default 35000)
 - MicroPython
     - introduced a configuration option to enable manual selection of devices
       (e.g. for unknown devices or inside the Linux container of ChromeOS)
diff -r e12589f1d408 -r a663a8be64da src/eric7/Debugger/DebugServer.py
--- a/src/eric7/Debugger/DebugServer.py	Tue Nov 22 16:33:30 2022 +0100
+++ b/src/eric7/Debugger/DebugServer.py	Wed Nov 23 10:48:46 2022 +0100
@@ -28,6 +28,14 @@
     "None": "DebuggerInterfaceNone",
 }
 
+NetworkInterfaceMapping = {
+    "all": QHostAddress.SpecialAddress.Any,
+    "allv4": QHostAddress.SpecialAddress.AnyIPv4,
+    "allv6": QHostAddress.SpecialAddress.AnyIPv6,
+    "localv4": QHostAddress.SpecialAddress.LocalHost,
+    "localv6": QHostAddress.SpecialAddress.LocalHostIPv6,
+}
+
 
 class DebugServer(QTcpServer):
     """
@@ -190,28 +198,34 @@
         self.__reportedWatchpointIssues = []
 
         self.networkInterface = Preferences.getDebugger("NetworkInterface")
-        if self.networkInterface == "all":
-            hostAddress = QHostAddress("0.0.0.0")
-            # QHostAddress.SpecialAddress.AnyIPv4)  # secok
-        elif self.networkInterface == "allv6":
-            hostAddress = QHostAddress("::")
-            # QHostAddress.SpecialAddress.AnyIPv6)
-        else:
-            hostAddress = QHostAddress(self.networkInterface)
+        hostAddress = (
+            QHostAddress(NetworkInterfaceMapping[self.networkInterface])
+            if self.networkInterface in NetworkInterfaceMapping
+            else QHostAddress(self.networkInterface)
+        )
         (
             self.networkInterfaceName,
             self.networkInterfaceIndex,
         ) = self.__getNetworkInterfaceAndIndex(self.networkInterface)
 
         if not preventPassiveDebugging and Preferences.getDebugger("PassiveDbgEnabled"):
-            sock = Preferences.getDebugger("PassiveDbgPort")  # default: 42424
-            self.listen(hostAddress, sock)
+            port = Preferences.getDebugger("PassiveDbgPort")  # default: 42424
+            self.listen(hostAddress, port)
             self.passive = True
             self.passiveClientExited = False
         else:
             if hostAddress.toString().lower().startswith("fe80"):
                 hostAddress.setScopeId(self.networkInterfaceName)
-            self.listen(hostAddress)
+            if Preferences.getDebugger("NetworkPortFixed"):
+                port = Preferences.getDebugger("NetworkPort")
+                res = self.listen(hostAddress, port)
+                if not res and Preferences.getDebugger("NetworkPortIncrement"):
+                    maxPort = port + 100  # try a maximum of 100 ports
+                    while not res and port < maxPort:
+                        port += 1
+                        res = self.listen(hostAddress, port)
+            else:
+                self.listen(hostAddress)
             self.passive = False
 
         self.debuggerInterface = None
@@ -261,13 +275,13 @@
         @return IP address or hostname
         @rtype str
         """
-        if self.networkInterface == "all":
-            if localhost:
+        if self.networkInterface in ("allv4", "localv4"):
+            if localhost or self.networkInterface == "localv4":
                 return "127.0.0.1"
             else:
                 return "{0}@@v4".format(QHostInfo.localHostName())
-        elif self.networkInterface == "allv6":
-            if localhost:
+        elif self.networkInterface in ("all", "allv6", "localv6"):
+            if localhost or self.networkInterface == "localv6":
                 return "::1"
             else:
                 return "{0}@@v6".format(QHostInfo.localHostName())
diff -r e12589f1d408 -r a663a8be64da src/eric7/EricNetwork/EricJsonServer.py
--- a/src/eric7/EricNetwork/EricJsonServer.py	Tue Nov 22 16:33:30 2022 +0100
+++ b/src/eric7/EricNetwork/EricJsonServer.py	Wed Nov 23 10:48:46 2022 +0100
@@ -54,20 +54,27 @@
 
         # setup the network interface
         networkInterface = Preferences.getDebugger("NetworkInterface")
-        if networkInterface == "all" or "." in networkInterface:
+        if networkInterface in ("allv4", "localv4") or "." in networkInterface:
             # IPv4
             self.__hostAddress = "127.0.0.1"
-        else:
+        elif networkInterface in ("all", "allv6", "localv6"):
             # IPv6
             self.__hostAddress = "::1"
+        else:
+            self.__hostAddress = networkInterface
         self.listen(QHostAddress(self.__hostAddress))
 
         self.newConnection.connect(self.handleNewConnection)
 
-        ## Note: Need the port if client is started external in debugger.
+        ## Note: Need the address and port if client is started external in debugger.
+        hostAddressStr = (
+            "[{0}]".format(self.__hostAddress)
+            if ":" in self.__hostAddress
+            else self.__hostAddress
+        )
         print(  # __IGNORE_WARNING_M801__
-            "JSON server ({1}) listening on: {0:d}".format(
-                self.serverPort(), self.__name
+            "JSON server ({2}) listening on: {0}:{1:d}".format(
+                hostAddressStr, self.serverPort(), self.__name
             )
         )
 
diff -r e12589f1d408 -r a663a8be64da src/eric7/EricNetwork/EricJsonStreamReader.py
--- a/src/eric7/EricNetwork/EricJsonStreamReader.py	Tue Nov 22 16:33:30 2022 +0100
+++ b/src/eric7/EricNetwork/EricJsonStreamReader.py	Wed Nov 23 10:48:46 2022 +0100
@@ -47,22 +47,29 @@
         # setup the network interface
         if ip is None:
             networkInterface = Preferences.getDebugger("NetworkInterface")
-            if networkInterface == "all" or "." in networkInterface:
+            if networkInterface in ("allv4", "localv4") or "." in networkInterface:
                 # IPv4
                 self.__hostAddress = "127.0.0.1"
-            else:
+            elif networkInterface in ("all", "allv6", "localv6"):
                 # IPv6
                 self.__hostAddress = "::1"
+            else:
+                self.__hostAddress = networkInterface
         else:
             self.__hostAddress = ip
         self.listen(QHostAddress(self.__hostAddress))
 
         self.newConnection.connect(self.handleNewConnection)
 
-        ## Note: Need the port if writer is started external in debugger.
+        ## Note: Need the address and port if client is started external in debugger.
+        hostAddressStr = (
+            "[{0}]".format(self.__hostAddress)
+            if ":" in self.__hostAddress
+            else self.__hostAddress
+        )
         print(  # __IGNORE_WARNING_M801__
-            "JSON reader ({1}) listening on: {0:d}".format(
-                self.serverPort(), self.__name
+            "JSON server ({2}) listening on: {0}:{1:d}".format(
+                hostAddressStr, self.serverPort(), self.__name
             )
         )
 
diff -r e12589f1d408 -r a663a8be64da src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.py
--- a/src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.py	Tue Nov 22 16:33:30 2022 +0100
+++ b/src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.py	Wed Nov 23 10:48:46 2022 +0100
@@ -7,8 +7,6 @@
 Module implementing the Debugger General configuration page.
 """
 
-import re
-
 from PyQt6.QtCore import QAbstractItemModel, QModelIndex, Qt, pyqtSlot
 from PyQt6.QtGui import QBrush, QColor
 from PyQt6.QtNetwork import QAbstractSocket, QHostAddress, QNetworkInterface
@@ -58,43 +56,66 @@
             self.dbgTranslationLocalEdit
         )
 
-        # set initial values
-        interfaces = []
+        self.interfaceSelectorComboBox.addItem(
+            self.tr("All Network Interfaces (IPv4 & IPv6)"),
+            "all",
+        )
+        self.interfaceSelectorComboBox.addItem(
+            self.tr("All Network Interfaces (IPv4"),
+            "allv4",
+        )
+        self.interfaceSelectorComboBox.addItem(
+            self.tr("All Network Interfaces (IPv6)"),
+            "allv6",
+        )
+        self.interfaceSelectorComboBox.addItem(
+            self.tr("Localhost (IPv4)"),
+            "localv4",
+        )
+        self.interfaceSelectorComboBox.addItem(
+            self.tr("Localhost (IPv6)"),
+            "localv6",
+        )
+        self.interfaceSelectorComboBox.addItem(
+            self.tr("Selected Interface"),
+            "selected",
+        )
+
         networkInterfaces = QNetworkInterface.allInterfaces()
         for networkInterface in networkInterfaces:
             addressEntries = networkInterface.addressEntries()
             if len(addressEntries) > 0:
                 for addressEntry in addressEntries:
-                    interfaces.append(
-                        "{0} ({1})".format(
-                            networkInterface.humanReadableName(),
-                            addressEntry.ip().toString(),
-                        )
+                    ip = addressEntry.ip().toString()
+                    self.interfacesCombo.addItem(
+                        "{0} ({1})".format(networkInterface.humanReadableName(), ip), ip
                     )
-        self.interfacesCombo.addItems(interfaces)
+
+        # set initial values
         interface = Preferences.getDebugger("NetworkInterface")
-        # TODO: change config 'all' to 'allv4'
-        # TODO: change radiobutton selection to combo box and include
-        #       - Localhost (IPv4)    (localv4)
-        #       - LocalHost (IPv6)    (localv6)
-        #       - Any (IPv4)          (allv4)
-        #       - Any (IPv6)          (allv6)
-        #       - Any (IPv4 and IPv6) (all)
-        #       - Selected Interface
+        selectorIndex = self.interfaceSelectorComboBox.findData(interface)
+        if selectorIndex != -1:
+            self.interfaceSelectorComboBox.setCurrentIndex(selectorIndex)
+        else:
+            # Interface given by IP address
+            self.interfaceSelectorComboBox.setCurrentIndex(
+                self.interfaceSelectorComboBox.count() - 1
+            )
+            self.interfacesCombo.setCurrentIndex(
+                self.interfacesCombo.findData(interface)
+            )
+        self.on_interfaceSelectorComboBox_currentIndexChanged(
+            self.interfacesCombo.currentIndex()
+        )
+        self.serverPortStaticGroup.setChecked(
+            Preferences.getDebugger("NetworkPortFixed")
+        )
+        self.serverPortIncrementCheckBox.setChecked(
+            Preferences.getDebugger("NetworkPortIncrement")
+        )
+        self.serverPortSpinBox.setValue(Preferences.getDebugger("NetworkPort"))
         # TODO: allow to listen on a specific port with auto-increment if port is in
         #       use already
-        if interface == "all":
-            self.allInterfacesButton.setChecked(True)
-        elif interface == "allv6":
-            self.all6InterfacesButton.setChecked(True)
-        else:
-            self.selectedInterfaceButton.setChecked(True)
-            index = -1
-            for i in range(len(interfaces)):
-                if re.fullmatch(".*{0}.*".format(interface), interfaces[i]):
-                    index = i
-                    break
-            self.interfacesCombo.setCurrentIndex(index)
 
         self.allowedHostsList.addItems(Preferences.getDebugger("AllowedHosts"))
 
@@ -193,17 +214,17 @@
             "PassiveDbgType", self.passiveDbgBackendCombo.currentText()
         )
 
-        if self.allInterfacesButton.isChecked():
-            Preferences.setDebugger("NetworkInterface", "all")
-        elif self.all6InterfacesButton.isChecked():
-            Preferences.setDebugger("NetworkInterface", "allv6")
-        else:
-            interface = self.interfacesCombo.currentText()
-            interface = interface.split("(")[1].split(")")[0]
-            if not interface:
-                Preferences.setDebugger("NetworkInterface", "all")
-            else:
-                Preferences.setDebugger("NetworkInterface", interface)
+        interface = self.interfaceSelectorComboBox.currentData()
+        if interface == "selected":
+            interface = self.interfacesCombo.currentData()
+        Preferences.setDebugger("NetworkInterface", interface)
+        Preferences.setDebugger(
+            "NetworkPortFixed", self.serverPortStaticGroup.isChecked()
+        )
+        Preferences.setDebugger(
+            "NetworkPortIncrement", self.serverPortIncrementCheckBox.isChecked()
+        )
+        Preferences.setDebugger("NetworkPort", self.serverPortSpinBox.value())
 
         allowedHosts = []
         for row in range(self.allowedHostsList.count()):
@@ -255,6 +276,18 @@
             "AutoViewSourceCode", self.autoViewSourcecodeCheckBox.isChecked()
         )
 
+    @pyqtSlot(int)
+    def on_interfaceSelectorComboBox_currentIndexChanged(self, index):
+        """
+        Private slot to handle the selection of a network interface type.
+
+        @param index index of the selected entry
+        @type int
+        """
+        self.interfacesCombo.setEnabled(
+            index == self.interfaceSelectorComboBox.count() - 1
+        )
+
     def on_allowedHostsList_currentItemChanged(self, current, previous):
         """
         Private method set the state of the edit and delete button.
diff -r e12589f1d408 -r a663a8be64da src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.ui
--- a/src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.ui	Tue Nov 22 16:33:30 2022 +0100
+++ b/src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.ui	Wed Nov 23 10:48:46 2022 +0100
@@ -7,10 +7,10 @@
     <x>0</x>
     <y>0</y>
     <width>550</width>
-    <height>1694</height>
+    <height>1804</height>
    </rect>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout_7">
+  <layout class="QVBoxLayout" name="verticalLayout_9">
    <item>
     <widget class="QLabel" name="headerLabel">
      <property name="text">
@@ -36,8 +36,8 @@
      <property name="title">
       <string>Network Interface</string>
      </property>
-     <layout class="QGridLayout" name="gridLayout_2">
-      <item row="0" column="0" colspan="4">
+     <layout class="QVBoxLayout" name="verticalLayout_7">
+      <item>
        <widget class="QLabel" name="TextLabel1_2_3">
         <property name="text">
          <string>&lt;font color=&quot;#FF0000&quot;&gt;&lt;b&gt;Note:&lt;/b&gt; These settings are activated at the next startup of the application.&lt;/font&gt;</string>
@@ -47,50 +47,14 @@
         </property>
        </widget>
       </item>
-      <item row="1" column="0" colspan="2">
-       <widget class="QRadioButton" name="allInterfacesButton">
+      <item>
+       <widget class="QComboBox" name="interfaceSelectorComboBox">
         <property name="toolTip">
-         <string>Select to listen on all available network interfaces (IPv4 mode)</string>
-        </property>
-        <property name="text">
-         <string>All network interfaces (IPv4)</string>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="2">
-       <widget class="QRadioButton" name="all6InterfacesButton">
-        <property name="toolTip">
-         <string>Select to listen on all available network interfaces (IPv6 mode)</string>
-        </property>
-        <property name="text">
-         <string>All network interfaces (IPv6)</string>
+         <string>Select the interface(s) to listen on</string>
         </property>
        </widget>
       </item>
-      <item row="1" column="3">
-       <spacer name="horizontalSpacer_5">
-        <property name="orientation">
-         <enum>Qt::Horizontal</enum>
-        </property>
-        <property name="sizeHint" stdset="0">
-         <size>
-          <width>103</width>
-          <height>20</height>
-         </size>
-        </property>
-       </spacer>
-      </item>
-      <item row="2" column="0">
-       <widget class="QRadioButton" name="selectedInterfaceButton">
-        <property name="toolTip">
-         <string>Select to listen on the configured interface</string>
-        </property>
-        <property name="text">
-         <string>Only selected interface</string>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="1" colspan="3">
+      <item>
        <widget class="QComboBox" name="interfacesCombo">
         <property name="enabled">
          <bool>false</bool>
@@ -100,6 +64,73 @@
         </property>
        </widget>
       </item>
+      <item>
+       <widget class="QGroupBox" name="serverPortStaticGroup">
+        <property name="toolTip">
+         <string>Select to listen on a fixed network port</string>
+        </property>
+        <property name="title">
+         <string>Static Server Port</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="checked">
+         <bool>false</bool>
+        </property>
+        <layout class="QGridLayout" name="gridLayout_5">
+         <item row="0" column="0">
+          <widget class="QLabel" name="label_5">
+           <property name="text">
+            <string>Server Port:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QSpinBox" name="serverPortSpinBox">
+           <property name="toolTip">
+            <string>Enter the port number to listen on</string>
+           </property>
+           <property name="minimum">
+            <number>1025</number>
+           </property>
+           <property name="maximum">
+            <number>65535</number>
+           </property>
+           <property name="singleStep">
+            <number>1</number>
+           </property>
+           <property name="value">
+            <number>35000</number>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="2">
+          <spacer name="horizontalSpacer_6">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>333</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item row="1" column="0" colspan="3">
+          <widget class="QCheckBox" name="serverPortIncrementCheckBox">
+           <property name="toolTip">
+            <string>Select to increment the server port to listen on if the configured one is unavailable</string>
+           </property>
+           <property name="text">
+            <string>Increment server port if unavailable</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
      </layout>
     </widget>
    </item>
@@ -836,10 +867,11 @@
   </layout>
  </widget>
  <tabstops>
-  <tabstop>allInterfacesButton</tabstop>
-  <tabstop>all6InterfacesButton</tabstop>
-  <tabstop>selectedInterfaceButton</tabstop>
+  <tabstop>interfaceSelectorComboBox</tabstop>
   <tabstop>interfacesCombo</tabstop>
+  <tabstop>serverPortStaticGroup</tabstop>
+  <tabstop>serverPortSpinBox</tabstop>
+  <tabstop>serverPortIncrementCheckBox</tabstop>
   <tabstop>allowedHostsList</tabstop>
   <tabstop>addAllowedHostButton</tabstop>
   <tabstop>editAllowedHostButton</tabstop>
@@ -880,12 +912,12 @@
    <slot>setEnabled(bool)</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>121</x>
-     <y>467</y>
+     <x>154</x>
+     <y>730</y>
     </hint>
     <hint type="destinationlabel">
-     <x>107</x>
-     <y>498</y>
+     <x>140</x>
+     <y>763</y>
     </hint>
    </hints>
   </connection>
@@ -896,28 +928,12 @@
    <slot>setEnabled(bool)</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>219</x>
-     <y>467</y>
+     <x>252</x>
+     <y>730</y>
     </hint>
     <hint type="destinationlabel">
-     <x>205</x>
-     <y>498</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>selectedInterfaceButton</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>interfacesCombo</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>587</x>
-     <y>107</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>307</x>
-     <y>137</y>
+     <x>218</x>
+     <y>763</y>
     </hint>
    </hints>
   </connection>
@@ -928,12 +944,12 @@
    <slot>setEnabled(bool)</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>78</x>
-     <y>467</y>
+     <x>111</x>
+     <y>730</y>
     </hint>
     <hint type="destinationlabel">
-     <x>410</x>
-     <y>498</y>
+     <x>148</x>
+     <y>795</y>
     </hint>
    </hints>
   </connection>
@@ -944,12 +960,12 @@
    <slot>setEnabled(bool)</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>257</x>
-     <y>467</y>
+     <x>290</x>
+     <y>730</y>
     </hint>
     <hint type="destinationlabel">
-     <x>484</x>
-     <y>497</y>
+     <x>233</x>
+     <y>795</y>
     </hint>
    </hints>
   </connection>
diff -r e12589f1d408 -r a663a8be64da src/eric7/Utilities/BackgroundService.py
--- a/src/eric7/Utilities/BackgroundService.py	Tue Nov 22 16:33:30 2022 +0100
+++ b/src/eric7/Utilities/BackgroundService.py	Wed Nov 23 10:48:46 2022 +0100
@@ -56,18 +56,27 @@
         self.services = {}
 
         networkInterface = Preferences.getDebugger("NetworkInterface")
-        if networkInterface == "all" or "." in networkInterface:
-            self.hostAddress = "127.0.0.1"
+        if networkInterface in ("allv4", "localv4") or "." in networkInterface:
+            # IPv4
+            self.__hostAddress = "127.0.0.1"
+        elif networkInterface in ("all", "allv6", "localv6"):
+            # IPv6
+            self.__hostAddress = "::1"
         else:
-            self.hostAddress = "::1"
-        self.listen(QHostAddress(self.hostAddress))
+            self.__hostAddress = networkInterface
+        self.listen(QHostAddress(self.__hostAddress))
 
         self.newConnection.connect(self.on_newConnection)
 
+        ## Note: Need the address and port if started external in debugger:
         port = self.serverPort()
-        ## Note: Need the port if started external in debugger:
-        print("Background Service listening on: {0:d}".format(port))
-        # __IGNORE_WARNING__
+        hostAddressStr = (
+            "[{0}]".format(self.__hostAddress)
+            if ":" in self.__hostAddress
+            else self.__hostAddress
+        )
+        print("Background Service listening on: {0}:{1:d}".format(hostAddressStr, port))
+        # __IGNORE_WARNING_M801__
 
         interpreter = self.__getPythonInterpreter()
         if interpreter:
@@ -112,7 +121,7 @@
         proc.setProcessChannelMode(QProcess.ProcessChannelMode.ForwardedChannels)
         args = [
             backgroundClient,
-            self.hostAddress,
+            self.__hostAddress,
             str(port),
             str(Preferences.getUI("BackgroundServiceProcesses")),
             Globals.getPythonLibraryDirectory(),

eric ide

mercurial