From 771b1785161c9fcc822e17e26499c0d968ff17d2 Mon Sep 17 00:00:00 2001 From: Qubasa Date: Fri, 6 Dec 2024 12:18:21 +0100 Subject: [PATCH] clan-cli: made run_no_stdout runOpts compatible and make time table thread safe --- pkgs/clan-cli/clan_cli/api/directory.py | 3 +- pkgs/clan-cli/clan_cli/cmd.py | 65 ++++++++++--------------- pkgs/clan-cli/clan_cli/machines/list.py | 4 +- 3 files changed, 30 insertions(+), 42 deletions(-) diff --git a/pkgs/clan-cli/clan_cli/api/directory.py b/pkgs/clan-cli/clan_cli/api/directory.py index 4a40ad24e..6adab0d4b 100644 --- a/pkgs/clan-cli/clan_cli/api/directory.py +++ b/pkgs/clan-cli/clan_cli/api/directory.py @@ -4,6 +4,7 @@ from dataclasses import dataclass, field from pathlib import Path from typing import Any, Literal +from clan_cli.cmd import RunOpts from clan_cli.errors import ClanError from clan_cli.nix import nix_shell, run_no_stdout @@ -154,7 +155,7 @@ def show_block_devices(options: BlockDeviceOptions) -> Blockdevices: "PATH,NAME,RM,SIZE,RO,MOUNTPOINTS,TYPE,ID-LINK", ], ) - proc = run_no_stdout(cmd, needs_user_terminal=True) + proc = run_no_stdout(cmd, RunOpts(needs_user_terminal=True)) res = proc.stdout.strip() blk_info: dict[str, Any] = json.loads(res) diff --git a/pkgs/clan-cli/clan_cli/cmd.py b/pkgs/clan-cli/clan_cli/cmd.py index 34650d0bc..2db7b71c3 100644 --- a/pkgs/clan-cli/clan_cli/cmd.py +++ b/pkgs/clan-cli/clan_cli/cmd.py @@ -6,6 +6,7 @@ import select import shlex import signal import subprocess +import threading import time import timeit import weakref @@ -212,30 +213,33 @@ class TimeTable: def __init__(self) -> None: self.table: dict[str, float] = {} + self.lock = threading.Lock() weakref.finalize(self, self.table_print) def table_print(self) -> None: - print("======== CMD TIMETABLE ========") + with self.lock: + print("======== CMD TIMETABLE ========") - # Sort the table by time in descending order - sorted_table = sorted( - self.table.items(), key=lambda item: item[1], reverse=True - ) + # Sort the table by time in descending order + sorted_table = sorted( + self.table.items(), key=lambda item: item[1], reverse=True + ) - for k, v in sorted_table: - # Check if timedelta is greater than 1 second - if v > 1: - # Print in red - print(f"\033[91mTook {v}s\033[0m for command: '{k}'") - else: - # Print in default color - print(f"Took {v} for command: '{k}'") + for k, v in sorted_table: + # Check if timedelta is greater than 1 second + if v > 1: + # Print in red + print(f"\033[91mTook {v}s\033[0m for command: '{k}'") + else: + # Print in default color + print(f"Took {v} for command: '{k}'") def add(self, cmd: str, time: float) -> None: - if cmd in self.table: - self.table[cmd] += time - else: - self.table[cmd] = time + with self.lock: + if cmd in self.table: + self.table[cmd] += time + else: + self.table[cmd] = time TIME_TABLE = None @@ -339,34 +343,17 @@ def run( def run_no_stdout( cmd: list[str], - *, - env: dict[str, str] | None = None, - cwd: Path | None = None, - log: Log = Log.STDERR, - prefix: str | None = None, - check: bool = True, - error_msg: str | None = None, - needs_user_terminal: bool = False, - shell: bool = False, + opts: RunOpts | None = None, ) -> CmdOut: """ Like run, but automatically suppresses all output, if not in DEBUG log level. If in DEBUG log level the stdout of commands will be shown. """ - opts = RunOpts( - env=env, - cwd=cwd, - log=log, - check=check, - error_msg=error_msg, - needs_user_terminal=needs_user_terminal, - shell=shell, - prefix=prefix, - ) + if opts is None: + opts = RunOpts() + if cmdlog.isEnabledFor(logging.DEBUG): - opts.log = log if log.value > Log.STDERR.value else Log.STDERR - else: - opts.log = log + opts.log = opts.log if opts.log.value > Log.STDERR.value else Log.STDERR return run( cmd, diff --git a/pkgs/clan-cli/clan_cli/machines/list.py b/pkgs/clan-cli/clan_cli/machines/list.py index ef41d42b3..0ccdd494f 100644 --- a/pkgs/clan-cli/clan_cli/machines/list.py +++ b/pkgs/clan-cli/clan_cli/machines/list.py @@ -8,7 +8,7 @@ from typing import Literal from clan_cli.api import API from clan_cli.api.modules import parse_frontmatter from clan_cli.api.serde import dataclass_to_dict -from clan_cli.cmd import run_no_stdout +from clan_cli.cmd import RunOpts, run_no_stdout from clan_cli.completions import add_dynamic_completer, complete_tags from clan_cli.dirs import specific_machine_dir from clan_cli.errors import ClanCmdError, ClanError @@ -145,7 +145,7 @@ def check_machine_online( ], ) try: - proc = run_no_stdout(cmd, needs_user_terminal=True) + proc = run_no_stdout(cmd, RunOpts(needs_user_terminal=True)) if proc.returncode != 0: return "Offline" except ClanCmdError: