1# Copyright (c) 2023 Nordic Semiconductor ASA 2# 3# SPDX-License-Identifier: Apache-2.0 4 5from __future__ import annotations 6 7import contextlib 8import logging 9import os 10import platform 11import shlex 12import signal 13import subprocess 14import time 15 16import psutil 17 18_WINDOWS = platform.system() == 'Windows' 19 20 21def log_command(logger: logging.Logger, msg: str, args: list, level: int = logging.DEBUG) -> None: 22 """ 23 Platform-independent helper for logging subprocess invocations. 24 25 Will log a command string that can be copy/pasted into a POSIX 26 shell on POSIX platforms. This is not available on Windows, so 27 the entire args array is logged instead. 28 29 :param logger: logging.Logger to use 30 :param msg: message to associate with the command 31 :param args: argument list as passed to subprocess module 32 :param level: log level 33 """ 34 msg = f'{msg}: %s' 35 if _WINDOWS: 36 logger.log(level, msg, str(args)) 37 else: 38 logger.log(level, msg, shlex.join(args)) 39 40 41def terminate_process(proc: subprocess.Popen) -> None: 42 """ 43 Try to terminate provided process and all its subprocesses recursively. 44 """ 45 with contextlib.suppress(ProcessLookupError, psutil.NoSuchProcess): 46 for child in psutil.Process(proc.pid).children(recursive=True): 47 with contextlib.suppress(ProcessLookupError, psutil.NoSuchProcess): 48 os.kill(child.pid, signal.SIGTERM) 49 proc.terminate() 50 # sleep for a while before attempting to kill 51 time.sleep(0.5) 52 proc.kill() 53