Optimized warning sounds

This commit is contained in:
Kevin Veen-Birkenbach 2025-05-17 19:48:29 +02:00
parent 338f66352a
commit c1b94778b4
No known key found for this signature in database
GPG Key ID: 44D8F11FD62F878E

135
main.py
View File

@ -6,6 +6,7 @@ import subprocess
import sys import sys
import textwrap import textwrap
import threading import threading
import signal
from cli.sounds import Sound from cli.sounds import Sound
@ -25,7 +26,6 @@ def list_cli_commands(cli_dir):
) )
def extract_description_via_help(cli_script_path): def extract_description_via_help(cli_script_path):
"""Run `script --help` and extract the first non-usage line after usage block."""
try: try:
result = subprocess.run( result = subprocess.run(
[sys.executable, cli_script_path, "--help"], [sys.executable, cli_script_path, "--help"],
@ -50,119 +50,88 @@ def play_start_intro():
Sound.play_start_sound() Sound.play_start_sound()
Sound.play_cymais_intro_sound() Sound.play_cymais_intro_sound()
if __name__ == "__main__": def failure_with_warning_loop():
# Detect --no-sound option early Sound.play_finished_failed_sound()
no_sound = '--no-sound' in sys.argv print("Warning: command failed. Press Ctrl+C to stop sound warnings.")
if no_sound:
sys.argv.remove('--no-sound')
# Warning loop for failures
def warning_loop():
try: try:
while True: while True:
Sound.play_warning_sound() Sound.play_warning_sound()
except Exception: except KeyboardInterrupt:
pass print("Warnings stopped by user.")
# Start intro sounds in background if enabled if __name__ == "__main__":
if not no_sound: # Parse --no-sound early and remove from args
threading.Thread(target=play_start_intro, daemon=True).start() no_sound = False
if '--no-sound' in sys.argv:
script_dir = os.path.dirname(os.path.realpath(__file__)) no_sound = True
import signal
# Handler for segmentation faults
def segv_handler(signum, frame):
# Play failure and warning loop on segmentation fault
if not no_sound:
Sound.play_finished_failed_sound()
stop_event = threading.Event()
threading.Thread(target=warning_loop, args=(stop_event,), daemon=True).start()
print("Segmentation fault detected. Press Enter to stop warnings.")
input()
if not no_sound:
stop_event.set()
sys.exit(1)
signal.signal(signal.SIGSEGV, segv_handler)
# Detect --no-sound option
# Detect --no-sound option
no_sound = '--no-sound' in sys.argv
if no_sound:
sys.argv.remove('--no-sound') sys.argv.remove('--no-sound')
# Start intro sounds in background if enabled # Setup segfault handler to catch crashes
def segv_handler(signum, frame):
if not no_sound:
Sound.play_finished_failed_sound()
# Loop warning until interrupted
try:
while True:
Sound.play_warning_sound()
except KeyboardInterrupt:
pass
print("Segmentation fault detected. Exiting.")
sys.exit(1)
signal.signal(signal.SIGSEGV, segv_handler)
# Play intro sounds
if not no_sound: if not no_sound:
threading.Thread(target=play_start_intro, daemon=True).start() threading.Thread(target=play_start_intro, daemon=True).start()
# Change to script directory
script_dir = os.path.dirname(os.path.realpath(__file__)) script_dir = os.path.dirname(os.path.realpath(__file__))
cli_dir = os.path.join(script_dir, "cli") cli_dir = os.path.join(script_dir, "cli")
os.chdir(script_dir) os.chdir(script_dir)
available_cli_commands = list_cli_commands(cli_dir) available_cli_commands = list_cli_commands(cli_dir)
# Special case: user ran `cymais <cmd> --help` # Handle help invocation
if len(sys.argv) >= 3 and sys.argv[1] in available_cli_commands and sys.argv[2] == "--help": if len(sys.argv) == 1 or sys.argv[1] in ('-h', '--help'):
cli_script_path = os.path.join(cli_dir, f"{sys.argv[1]}.py") print("CyMaIS CLI proxy to tools in ./cli/")
subprocess.run([sys.executable, cli_script_path, "--help"]) print("Usage: cymais [--no-sound] <command> [options]")
sys.exit(0) print("Options:")
print(" --no-sound Suppress all sounds during execution")
# Global help print(" -h, --help Show this help message and exit")
if "--help" in sys.argv or "-h" in sys.argv or len(sys.argv) == 1:
print("CyMaIS CLI proxy to tools in ./cli/\n")
print("Usage:")
print(" cymais <command> [options]\n")
print("Available commands:") print("Available commands:")
for cmd in available_cli_commands: for cmd in available_cli_commands:
path = os.path.join(cli_dir, f"{cmd}.py") path = os.path.join(cli_dir, f"{cmd}.py")
desc = extract_description_via_help(path) desc = extract_description_via_help(path)
print(format_command_help(cmd, desc)) print(format_command_help(cmd, desc))
print("\nUse 'cymais <command> --help' for details.")
sys.exit(0) sys.exit(0)
# Execute command and handle exit codes or signals # Special-case per-command help
try: if len(sys.argv) >= 3 and sys.argv[1] in available_cli_commands and sys.argv[2] in ('-h', '--help'):
subprocess.run([sys.executable, os.path.join(cli_dir, f"{sys.argv[1]}.py"), "--help"])
sys.exit(0)
# Execute chosen command
parser = argparse.ArgumentParser(add_help=False) parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("cli_command", choices=available_cli_commands) parser.add_argument('cli_command', choices=available_cli_commands)
parser.add_argument("cli_args", nargs=argparse.REMAINDER) parser.add_argument('cli_args', nargs=argparse.REMAINDER)
args = parser.parse_args() args = parser.parse_args()
cli_script_path = os.path.join(cli_dir, f"{args.cli_command}.py") cmd_path = os.path.join(cli_dir, f"{args.cli_command}.py")
full_cmd = [sys.executable, cli_script_path] + args.cli_args full_cmd = [sys.executable, cmd_path] + args.cli_args
try:
proc = subprocess.Popen(full_cmd) proc = subprocess.Popen(full_cmd)
proc.wait() proc.wait()
retcode = proc.returncode rc = proc.returncode
if rc != 0:
if retcode != 0: print(f"Command '{args.cli_command}' failed with exit code {rc}.")
# Failure sound failure_with_warning_loop()
if not no_sound: sys.exit(rc)
Sound.play_finished_failed_sound()
sig_msg = f" (terminated by signal {-retcode})" if retcode < 0 else ''
print(f"Command failed with exit code {retcode}{sig_msg}. Press Ctrl+C to stop warnings.")
if not no_sound:
try:
while True:
Sound.play_warning_sound()
except KeyboardInterrupt:
pass
sys.exit(retcode)
else: else:
if not no_sound: if not no_sound:
Sound.play_finished_successfully_sound() Sound.play_finished_successfully_sound()
sys.exit(0) sys.exit(0)
except Exception as e: except Exception as e:
# Exception handling print(f"Exception running command: {e}")
if not no_sound: failure_with_warning_loop()
Sound.play_finished_failed_sound()
print(f"An exception occurred: {e}. Press Ctrl+C to stop warnings.")
if not no_sound:
try:
while True:
Sound.play_warning_sound()
except KeyboardInterrupt:
pass
sys.exit(1) sys.exit(1)