|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2024 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the file system interface to the eric-ide server. |
|
8 """ |
|
9 |
|
10 from PyQt6.QtCore import QEventLoop, QObject, pyqtSignal, pyqtSlot |
|
11 |
|
12 from eric7.EricWidgets import EricMessageBox |
|
13 from eric7.EricWidgets.EricApplication import ericApp |
|
14 from eric7.RemoteServer.EricRequestCategory import EricRequestCategory |
|
15 from eric7.SystemUtilities import FileSystemUtilities |
|
16 |
|
17 |
|
18 # TODO: sanitize all file names with FileSystemUtilities.plainFileName() |
|
19 class EricServerDebuggerInterface(QObject): |
|
20 """ |
|
21 Class implementing the file system interface to the eric-ide server. |
|
22 """ |
|
23 |
|
24 debugClientResponse = pyqtSignal(str) |
|
25 |
|
26 def __init__(self, serverInterface): |
|
27 """ |
|
28 Constructor |
|
29 |
|
30 @param serverInterface reference to the eric-ide server interface |
|
31 @type EricServerInterface |
|
32 """ |
|
33 super().__init__(parent=serverInterface) |
|
34 |
|
35 self.__serverInterface = serverInterface |
|
36 |
|
37 self.__replyMethodMapping = { |
|
38 "DebuggerRequestError": self.__handleDbgRequestError, |
|
39 "DebugClientResponse": self.__handleDbgClientResponse, |
|
40 "DebugClientDisconnected": self.__handleDbgClientDisconnected, |
|
41 "LastDebugClientExited": self.__handleLastDbgClientExited, |
|
42 } |
|
43 |
|
44 # connect some signals |
|
45 self.__serverInterface.remoteDebuggerReply.connect(self.__handleDebuggerReply) |
|
46 |
|
47 def sendClientCommand(self, debuggerId, jsonCommand): |
|
48 """ |
|
49 Public method to rely a debug client command via the eric-ide server. |
|
50 |
|
51 @param debuggerId id of the debug client to send the command to |
|
52 @type str |
|
53 @param jsonCommand JSON encoded command dictionary to be relayed |
|
54 @type str |
|
55 """ |
|
56 self.__serverInterface.sendJson( |
|
57 category=EricRequestCategory.Debugger, |
|
58 request="DebugClientCommand", |
|
59 params={"debugger_id": debuggerId, "command": jsonCommand}, |
|
60 ) |
|
61 |
|
62 @pyqtSlot(str, dict) |
|
63 def __handleDebuggerReply(self, reply, params): |
|
64 """ |
|
65 Private slot to handle a debugger reply from the eric-ide server. |
|
66 |
|
67 @param reply name of the server reply |
|
68 @type str |
|
69 @param params dictionary containing the reply data |
|
70 @type dict |
|
71 """ |
|
72 try: |
|
73 self.__replyMethodMapping[reply](params) |
|
74 except KeyError: |
|
75 EricMessageBox.critical( |
|
76 None, |
|
77 self.tr("Unknown Server Reply"), |
|
78 self.tr( |
|
79 "<p>The eric-ide server debugger interface sent the unknown reply" |
|
80 " <b>{0}</b>.</p>" |
|
81 ).format(reply), |
|
82 ) |
|
83 |
|
84 ####################################################################### |
|
85 ## Methods for handling of debug client replies. |
|
86 ####################################################################### |
|
87 |
|
88 def __handleDbgRequestError(self, params): |
|
89 """ |
|
90 Private method to handle an error reported by the debugger interface of |
|
91 the eric-ide server. |
|
92 |
|
93 @param params dictionary containing the reply data |
|
94 @type dict |
|
95 """ |
|
96 EricMessageBox.warning( |
|
97 None, |
|
98 self.tr("Debug Client Command"), |
|
99 self.tr( |
|
100 "<p>The IDE received an error message.</p><p>Error: {0}</p>" |
|
101 ).format(params["Error"]), |
|
102 ) |
|
103 |
|
104 def __handleDbgClientResponse(self, params): |
|
105 """ |
|
106 Private method to handle a response from a debug client connected to the |
|
107 eric-ide server. |
|
108 |
|
109 @param params dictionary containing the reply data |
|
110 @type dict |
|
111 """ |
|
112 self.debugClientResponse.emit(params["response"]) |
|
113 |
|
114 def __handleDbgClientDisconnected(self, params): |
|
115 """ |
|
116 Private method to handle a debug client disconnect report of the |
|
117 eric-ide server. |
|
118 |
|
119 @param params dictionary containing the reply data |
|
120 @type dict |
|
121 """ |
|
122 ericApp().getObject("DebugServer").signalClientDisconnected( |
|
123 params["debugger_id"] |
|
124 ) |
|
125 |
|
126 def __handleLastDbgClientExited(self, params): |
|
127 """ |
|
128 Private method to handle a report of the eric-ide server, that the last |
|
129 debug client has disconnected. |
|
130 |
|
131 @param params dictionary containing the reply data |
|
132 @type dict |
|
133 """ |
|
134 ericApp().getObject("DebugServer").signalLastClientExited() |
|
135 |
|
136 ####################################################################### |
|
137 ## Methods for sending debug server commands to the eric-ide server. |
|
138 ####################################################################### |
|
139 |
|
140 def startClient(self, interpreter, originalPathString, args, workingDir=""): |
|
141 """ |
|
142 Public method to send a command to start a debug client. |
|
143 |
|
144 @param interpreter path of the remote interpreter to be used |
|
145 @type str |
|
146 @param originalPathString original PATH environment variable |
|
147 @type str |
|
148 @param args list of command line parameters for the debug client |
|
149 @type list of str |
|
150 @param workingDir directory to start the debugger client in (defaults to "") |
|
151 @type str (optional) |
|
152 """ |
|
153 self.__serverInterface.sendJson( |
|
154 category=EricRequestCategory.Debugger, |
|
155 request="StartClient", |
|
156 params={ |
|
157 "interpreter": FileSystemUtilities.plainFileName(interpreter), |
|
158 "path": originalPathString, |
|
159 "arguments": args, |
|
160 "working_dir": FileSystemUtilities.plainFileName(workingDir), |
|
161 }, |
|
162 ) |
|
163 |
|
164 def stopClient(self): |
|
165 """ |
|
166 Public method to stop the debug client synchronously. |
|
167 """ |
|
168 if self.__serverInterface.isServerConnected(): |
|
169 loop = QEventLoop() |
|
170 |
|
171 def callback(reply, params): |
|
172 """ |
|
173 Function to handle the server reply |
|
174 |
|
175 @param reply name of the server reply |
|
176 @type str |
|
177 @param params dictionary containing the reply data |
|
178 @type dict |
|
179 """ |
|
180 if reply == "StopClient": |
|
181 loop.quit() |
|
182 |
|
183 self.__serverInterface.sendJson( |
|
184 category=EricRequestCategory.Debugger, |
|
185 request="StopClient", |
|
186 params={}, |
|
187 callback=callback, |
|
188 ) |
|
189 |
|
190 loop.exec() |