Skip to content

Commit 507ddc7

Browse files
enhancement for terminal_no_frok
1 parent 19e8820 commit 507ddc7

1 file changed

Lines changed: 29 additions & 16 deletions

File tree

moler/io/raw/terminal_no_fork.py

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ def __init__(
7272
self.target_prompt = target_prompt
7373
self._cmd = cmd
7474
self.set_prompt_cmd = set_prompt_cmd
75-
self._re_set_prompt_cmd = re.sub(
76-
"['\"].*['\"]", "", self.set_prompt_cmd.strip()
75+
self._re_set_prompt_cmd = re.escape(
76+
re.sub("['\"].*['\"]", "", self.set_prompt_cmd.strip())
7777
)
7878
self._terminal_delayafterclose = terminal_delayafterclose
7979
self._join_timeout = 10
@@ -131,28 +131,35 @@ def close(self) -> None:
131131
Close ThreadedTerminal connection & stop pulling thread.
132132
:return: None
133133
"""
134+
pulling_thread_alive = False
134135
if self.pulling_thread:
135136
try:
136137
self.pulling_thread.join(timeout=self._join_timeout)
137-
if self.pulling_thread.is_alive():
138+
pulling_thread_alive = self.pulling_thread.is_alive()
139+
if pulling_thread_alive:
138140
self.logger.warning(
139-
f"Pulling thread did not finish after {self._join_timeout} timeout."
141+
f"Pulling thread did not finish after {self._join_timeout}s timeout."
140142
)
141143
except Exception as ex:
142144
self.logger.warning(f"Exception while joining pulling thread: {ex}")
143145
self.moler_connection.shutdown()
144146
super().close()
145147

146-
if self._terminal and self._terminal.isalive():
148+
terminal = self._terminal
149+
if terminal and terminal.isalive():
147150
self._notify_on_disconnect()
148151
try:
149-
self._terminal.close(force=True)
152+
terminal.close(force=True)
150153
except Exception as ex:
151154
self.logger.warning(f"Exception while closing terminal: {ex}")
152-
self._terminal = None
155+
if not pulling_thread_alive:
156+
# Only drop the terminal reference if no thread can still touch it,
157+
# to avoid AttributeError on None inside pull_data.
158+
self._terminal = None
153159
self._shell_operable.clear()
154160
self._export_sent = False
155-
self.pulling_thread = None
161+
if not pulling_thread_alive:
162+
self.pulling_thread = None
156163
self.read_buffer = ""
157164

158165
def send(self, data: str) -> None:
@@ -184,24 +191,28 @@ def pull_data(self, pulling_done: threading.Event) -> None:
184191
"""
185192
logging.getLogger("moler_threads").debug(f"ENTER {self}")
186193
heartbeat = tracked_thread.report_alive()
187-
reads: List[int] = []
194+
reads: List = []
188195

189196
while not pulling_done.is_set():
190-
assert self._terminal is not None
197+
terminal = self._terminal
198+
if terminal is None:
199+
pulling_done.set()
200+
break
191201
if next(heartbeat):
192202
logging.getLogger("moler_threads").debug(f"ALIVE {self}")
193203
try:
194204
reads, _, _ = select.select(
195-
[self._terminal.fd], [], [], self._select_timeout
205+
[terminal.fd], [], [], self._select_timeout
196206
)
197207
except ValueError as exc:
198208
self.logger.warning(f"'{exc.__class__}: {exc}'")
199209
self._notify_on_disconnect()
200210
pulling_done.set()
211+
continue
201212

202-
if self._terminal.fd in reads:
213+
if terminal.fd in reads:
203214
try:
204-
data = self._terminal.read(self._read_buffer_size)
215+
data = terminal.read(self._read_buffer_size)
205216
self._log_debug_incoming_data(data)
206217
if self._shell_operable.is_set():
207218
self.data_received(data=data, recv_time=datetime.datetime.now())
@@ -224,16 +235,18 @@ def _verify_shell_is_operable(self, data: str) -> None:
224235
for line in lines:
225236
line = remove_all_known_special_chars(line)
226237
if (
227-
not re.search(self._re_set_prompt_cmd, line) and re.search(
228-
self.target_prompt, line) and not self._shell_operable.is_set()
238+
not re.search(self._re_set_prompt_cmd, line)
239+
and re.search(self.target_prompt, line)
229240
):
230241
self._notify_on_connect()
231242
self._shell_operable.set()
232243
self.data_received(
233244
data=self.read_buffer, recv_time=datetime.datetime.now()
234245
)
246+
self.read_buffer = ""
247+
return
235248
elif not self._export_sent and re.search(
236-
self.first_prompt, self.read_buffer, re.MULTILINE
249+
self.first_prompt, self.read_buffer
237250
):
238251
self.send(self.set_prompt_cmd)
239252
self._export_sent = True

0 commit comments

Comments
 (0)