Skip to content

Commit

Permalink
fix(pikspect, main: handle_sig_int): don't handle SIG_INT while runni…
Browse files Browse the repository at this point in the history
…ng pacman, (fixes actionless#551)
  • Loading branch information
actionless committed Mar 24, 2021
1 parent 92e1a38 commit 13d3e8c
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 30 deletions.
15 changes: 9 additions & 6 deletions pikaur/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import atexit
import io
from argparse import ArgumentError # pylint: disable=no-name-in-module
from typing import List, Optional, Callable, NoReturn
from typing import List, Optional, Callable

import pyalpm

Expand Down Expand Up @@ -43,7 +43,7 @@
AUR_REPOS_CACHE_PATH, PikaurConfig, _OLD_AUR_REPOS_CACHE_PATH, DATA_ROOT,
)
from .exceptions import SysExit
from .pikspect import TTYRestore
from .pikspect import TTYRestore, PikspectSignalHandler
from .install_cli import InstallPackagesCLI
from .search_cli import cli_search_packages
from .info_cli import cli_info_packages
Expand Down Expand Up @@ -400,14 +400,18 @@ def restore_tty() -> None:
TTYRestore.restore()


def handle_sig_int(*_whatever) -> NoReturn: # pragma: no cover
def handle_sig_int(*_whatever) -> None: # pragma: no cover
if signal_handler := PikspectSignalHandler.get():
return signal_handler(*_whatever) # pylint: disable=not-callable
if parse_args().pikaur_debug:
raise KeyboardInterrupt()
print_stderr("\n\nCanceled by user (SIGINT)", lock=False)
raise SysExit(125)


def main() -> None:
try:
args = parse_args()
parse_args()
except ArgumentError as exc:
print_stderr(exc)
sys.exit(22)
Expand All @@ -419,8 +423,7 @@ def main() -> None:

atexit.register(restore_tty)
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
if not args.pikaur_debug:
signal.signal(signal.SIGINT, handle_sig_int)
signal.signal(signal.SIGINT, handle_sig_int)

try:
cli_entry_point()
Expand Down
70 changes: 46 additions & 24 deletions pikaur/pikspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import fcntl
import os
import re
import signal
from multiprocessing.pool import ThreadPool
from time import sleep
from typing import List, Dict, TextIO, BinaryIO, Callable, Optional, Union
Expand Down Expand Up @@ -103,6 +104,23 @@ def _match(pattern: str, line: str) -> bool:
)


class PikspectSignalHandler():

signal_handler: Optional[Callable] = None

@classmethod
def set(cls, signal_handler: Callable) -> None:
cls.signal_handler = signal_handler

@classmethod
def clear(cls) -> None:
cls.signal_handler = None

@classmethod
def get(cls) -> Optional[Callable]:
return cls.signal_handler


class PikspectPopen(subprocess.Popen): # pylint: disable=too-many-instance-attributes

print_output: bool
Expand Down Expand Up @@ -157,30 +175,34 @@ def communicator_thread(self) -> int:
return self._wait(None)

def run(self) -> None:
with NestedTerminal() as real_term_geometry:
if 'sudo' in self.args:
subprocess.run(get_sudo_refresh_command(), check=True)
with open(self.pty_user_master, 'w') as self.pty_in:
with open(self.pty_cmd_master, 'rb', buffering=0) as self.pty_out:
set_terminal_geometry(
self.pty_out.fileno(),
columns=real_term_geometry.columns,
rows=real_term_geometry.lines
)
with ThreadPool(processes=3) as pool:
output_task = pool.apply_async(self.cmd_output_reader_thread, ())
input_task = pool.apply_async(self.user_input_reader_thread, ())
communicate_task = pool.apply_async(self.communicator_thread, ())
pool.close()

output_task.get()
sys.stdout.buffer.write(self._write_buffer)
sys.stdout.buffer.flush()
communicate_task.get()
input_task.get()
pool.join()
os.close(self.pty_cmd_slave)
os.close(self.pty_user_slave)
PikspectSignalHandler.set(lambda *_whatever: self.send_signal(signal.SIGINT))
try:
with NestedTerminal() as real_term_geometry:
if 'sudo' in self.args:
subprocess.run(get_sudo_refresh_command(), check=True)
with open(self.pty_user_master, 'w') as self.pty_in:
with open(self.pty_cmd_master, 'rb', buffering=0) as self.pty_out:
set_terminal_geometry(
self.pty_out.fileno(),
columns=real_term_geometry.columns,
rows=real_term_geometry.lines
)
with ThreadPool(processes=3) as pool:
output_task = pool.apply_async(self.cmd_output_reader_thread, ())
input_task = pool.apply_async(self.user_input_reader_thread, ())
communicate_task = pool.apply_async(self.communicator_thread, ())
pool.close()

output_task.get()
sys.stdout.buffer.write(self._write_buffer)
sys.stdout.buffer.flush()
communicate_task.get()
input_task.get()
pool.join()
finally:
PikspectSignalHandler.clear()
os.close(self.pty_cmd_slave)
os.close(self.pty_user_slave)

def check_questions(self) -> None:
# pylint: disable=too-many-branches
Expand Down

0 comments on commit 13d3e8c

Please sign in to comment.