From 926b053dc27969817f991451f9e70b52f870ebb9 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 28 Sep 2024 20:11:41 +0200 Subject: [PATCH] Fix return code when subprocess fails (#33) * fix: return 1 when a subprocess fails * chore: add type hints and docstrings in scripts.py; some linter fixes --------- Co-authored-by: Martin --- AppImageBuilder.test.Dockerfile | 9 +-- scc/scripts.py | 116 +++++++++++++++++--------------- 2 files changed, 68 insertions(+), 57 deletions(-) diff --git a/AppImageBuilder.test.Dockerfile b/AppImageBuilder.test.Dockerfile index 2b6e8d3c..a57a56ac 100644 --- a/AppImageBuilder.test.Dockerfile +++ b/AppImageBuilder.test.Dockerfile @@ -41,10 +41,11 @@ RUN </dev/null - cd squashfs-root/runtime/compat - ../../AppRun dependency-check - output=$(../../AppRun daemon --help 2>&1 | tee -a /dev/stderr) - if echo "${output}" | grep -q Error; then return 1; fi + ( + cd squashfs-root/runtime/compat + ../../AppRun dependency-check + ../../AppRun daemon --help + ) rm -f "${file}" done } diff --git a/scc/scripts.py b/scc/scripts.py index 7f1b5bd5..008bed56 100644 --- a/scc/scripts.py +++ b/scc/scripts.py @@ -3,38 +3,51 @@ Contains code for most of what can be done using 'scc' script. Created so scc-* stuff doesn't polute /usr/bin. """ -from scc.tools import init_logging, set_logging_level, find_binary -import os, sys, subprocess +from __future__ import annotations +import os +import subprocess +import sys +from typing import TYPE_CHECKING -class InvalidArguments(Exception): pass +if TYPE_CHECKING: + from io import TextIOWrapper -def cmd_daemon(argv0, argv): - """ Controls scc-daemon """ - # Actually just passes parameters to scc-daemon - scc_daemon = find_binary("scc-daemon") - subprocess.Popen([scc_daemon] + argv).communicate() +from scc.tools import find_binary, init_logging, set_logging_level -def help_daemon(): - scc_daemon = find_binary("scc-daemon") - subprocess.Popen([scc_daemon, "--help"]).communicate() +class InvalidArguments(Exception): + pass +def run_binary(binary_name: str, argv: list[str]) -> int: + """Run scc-daemon with passed parameters.""" + binary = find_binary(binary_name) + child = subprocess.Popen([binary] + argv) + child.communicate() + return child.returncode -def cmd_gui(argv0, argv): - """ Starts GUI """ - # Passes parameters to sc-controller - scc_daemon = find_binary("sc-controller") - subprocess.Popen([scc_daemon] + argv).communicate() +def cmd_daemon(argv0: str, argv: list[str]) -> int: + """Run scc-daemon with passed parameters.""" + return run_binary("scc-daemon", argv) -def help_gui(): - scc_daemon = find_binary("sc-controller") - subprocess.Popen([scc_daemon, "--help"]).communicate() +def help_daemon() -> int: + """Run scc-daemon --help.""" + return run_binary("scc-daemon", ["--help"]) -def cmd_test_evdev(argv0, argv): +def cmd_gui(argv0: str, argv: list[str]) -> int: + """Run sc-controller(GUI) with passed parameters.""" + return run_binary("sc-controller", argv) + + +def help_gui() -> int: + """Run sc-controller --help.""" + return run_binary("sc-controller", ["--help"]) + + +def cmd_test_evdev(argv0: str, argv: list[str]) -> int: """ Evdev driver test. Displays gamepad inputs using evdev driver. @@ -48,7 +61,7 @@ def cmd_test_evdev(argv0, argv): return evdevdrv_test(argv) -def cmd_test_hid(argv0, argv): +def cmd_test_hid(argv0: str, argv: list[str]) -> int: """ HID driver test. Displays gamepad inputs using hid driver. @@ -64,27 +77,26 @@ def cmd_test_hid(argv0, argv): return hiddrv_test(HIDController, argv) -def help_osd_keyboard(): +def help_osd_keyboard() -> None: import_osd() from scc.osd.keyboard import Keyboard return run_osd_tool(Keyboard(), "osd-keyboard", ["--help"]) -def cmd_osd_keyboard(argv0, argv): - """ Displays on-screen keyboard """ +def cmd_osd_keyboard(argv0: str, argv: list[str]) -> None: + """Display on-screen keyboard.""" import_osd() from scc.osd.keyboard import Keyboard return run_osd_tool(Keyboard(), argv0, argv) -def cmd_list_profiles(argv0, argv): - """ - Lists available profiles +def cmd_list_profiles(argv0: str, argv: list[str]) -> int: + """List available profiles. Usage: scc list-profiles [-a] Arguments: - -a Include names begining with dot + -a Include names begining with dot """ from scc.paths import get_profiles_path, get_default_profiles_path paths = [ get_default_profiles_path(), get_profiles_path() ] @@ -104,9 +116,8 @@ def cmd_list_profiles(argv0, argv): return 0 -def cmd_set_profile(argv0, argv): - """ - Sets controller profile +def cmd_set_profile(argv0: str, argv: list[str]) -> int: + """Set controller profile. Usage: scc set-profile [controller_id] "profile name" """ @@ -136,8 +147,8 @@ def cmd_set_profile(argv0, argv): return 0 -def cmd_info(argv0, argv): - """ Displays basic information about running driver """ +def cmd_info(argv0: str, argv: list[str]) -> int: + """Display basic information about running driver.""" s = connect_to_daemon() if s is None: return -1 # Daemon already sends situable info, so this is mostly reading @@ -151,12 +162,12 @@ def cmd_info(argv0, argv): line = line.strip("\r\n\t ") if line == "Ready.": break - elif line.startswith("Current profile:"): + if line.startswith("Current profile:"): global_profile = line continue - elif line.startswith("Controller:"): + if line.startswith("Controller:"): continue - elif line.startswith("Controller profile:"): + if line.startswith("Controller profile:"): any_controller = True elif line.startswith("Error:"): print(line) @@ -168,8 +179,8 @@ def cmd_info(argv0, argv): return 0 -def cmd_dependency_check(argv0, argv): - """ Checks if all required libraries are installed on this system """ +def cmd_dependency_check(argv0: str, argv: list[str]) -> int: + """Check if all required libraries are installed on this system.""" try: import gi gi.require_version('Gtk', '3.0') @@ -201,9 +212,8 @@ def cmd_dependency_check(argv0, argv): return 0 -def cmd_lock_inputs(argv0, argv, lock="Lock: "): - """ - Locks and prints pressed buttons, pads and sticks +def cmd_lock_inputs(argv0: str, argv: list[str], lock: str = "Lock: ") -> int: + """Lock and print pressed buttons, pads and sticks. Locks controller inputs and prints buttons, pads and stick as they are pressed or moved on controller. @@ -247,9 +257,8 @@ def cmd_lock_inputs(argv0, argv, lock="Lock: "): s.close() -def cmd_print_inputs(argv0, argv, lock="Lock: "): - """ - Prints pressed buttons, pads and sticks +def cmd_print_inputs(argv0: str, argv: list[str], lock: str = "Lock: ") -> int: + """Print pressed buttons, pads and sticks. Prints controller inputs and prints buttons, pads and stick as they are pressed or moved on controller, without locking them exclusivelly. @@ -268,12 +277,13 @@ def cmd_print_inputs(argv0, argv, lock="Lock: "): return cmd_lock_inputs(argv0, argv, lock="Observe: ") -def connect_to_daemon(): - """ - Returns socket connected to daemon or None if connection failed. +def connect_to_daemon() -> TextIOWrapper | None: + """Return socket connected to daemon or None if connection failed. + Outputs error message in later case. """ import socket + from scc.paths import get_daemon_socket try: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) @@ -284,7 +294,7 @@ def connect_to_daemon(): return s.makefile(mode="rw") -def check_error(s): +def check_error(s) -> bool: """ Reads line(s) from socket until "OK." or "Fail:" is read. Then return True if message is "OK." or prints message to stderr @@ -306,19 +316,19 @@ def check_error(s): return False -def sigint(*a): +def sigint(*a) -> None: print("\n*break*") sys.exit(0) -def import_osd(): +def import_osd() -> None: import gi gi.require_version('Gtk', '3.0') gi.require_version('Rsvg', '2.0') gi.require_version('GdkX11', '3.0') -def run_osd_tool(tool, argv0, argv): +def run_osd_tool(tool, argv0: str, argv: list[str]) -> None: import signal, argparse signal.signal(signal.SIGINT, sigint) @@ -333,7 +343,7 @@ def run_osd_tool(tool, argv0, argv): sys.exit(tool.get_exit_code()) -def show_help(command = None, out=sys.stdout): +def show_help(command = None, out=sys.stdout) -> int: names = [ x[4:] for x in globals() if x.startswith("cmd_") ] max_len = max([ len(x) for x in names ]) if command in names: @@ -361,7 +371,7 @@ def show_help(command = None, out=sys.stdout): return 0 -def main(): +def main() -> None: init_logging() if len(sys.argv) < 2: sys.exit(show_help())