From d6ed6ad9f5ed6a813be1e5b03f0e810356cd457e Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 11 Mar 2026 22:51:36 +1300 Subject: [PATCH] Enhance CLI actions and default handling Add timed follow, src/lib upload helpers, and store default startup pattern under default key. Made-with: Cursor --- cli.py | 71 +++++++++++++++++++++++++++++++++++++++++++++---------- device.py | 13 ++++++++-- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/cli.py b/cli.py index 0eb3235..2514618 100755 --- a/cli.py +++ b/cli.py @@ -139,6 +139,26 @@ def _get_ordered_actions(argv: List[str]) -> List[tuple]: if vals: actions.append(('upload', vals)) continue + if arg == '--src': + # Upload local DIR (default: ./src) to device root (:/ + local_dir = "src" + if i + 1 < len(argv) and not argv[i + 1].startswith('-'): + local_dir = argv[i + 1] + i += 2 + else: + i += 1 + # Use empty string as remote_dir to map to root on device + actions.append(('upload', [local_dir, ""])) + continue + if arg == '--lib': + # Upload local DIR to /lib on device + if i + 1 < len(argv): + local_dir = argv[i + 1] + actions.append(('upload', [local_dir, "lib"])) + i += 2 + else: + raise ValueError("--lib requires a directory argument") + continue if arg == '-e': actions.append(('erase_all', None)) i += 1 @@ -151,8 +171,19 @@ def _get_ordered_actions(argv: List[str]) -> List[tuple]: raise ValueError("--rm requires an argument") continue if arg in ('-f', '--follow'): - actions.append(('follow', None)) - i += 1 + # Optional duration in seconds: --follow [SECONDS] + follow_secs = None + if i + 1 < len(argv) and not argv[i + 1].startswith('-'): + try: + follow_secs = float(argv[i + 1]) + i += 2 + except ValueError: + # Not a number, treat as flag-only + i += 1 + actions.append(('follow', follow_secs)) + else: + actions.append(('follow', None)) + i += 1 continue # Skip non-action flags and their values if arg in _FLAGS_WITH_VALUE and i + 1 < len(argv): @@ -258,7 +289,7 @@ Examples: parser.add_argument( "--default", metavar="PATTERN", - help="Default/startup pattern (startup_preset in settings.json)" + help="Default/startup pattern (stored as 'default' in settings.json)" ) parser.add_argument( @@ -276,8 +307,11 @@ Examples: parser.add_argument( "-f", "--follow", - action="store_true", - help="Follow device output continuously (like tail -f)" + nargs="?", + const=None, + type=float, + metavar="SECONDS", + help="Follow device output continuously (like tail -f). Optionally specify SECONDS to limit follow duration." ) parser.add_argument( @@ -293,6 +327,20 @@ Examples: help="Upload a directory recursively to the device. Usage: -u SRC [DEST] (DEST is optional, defaults to basename of SRC)" ) + parser.add_argument( + "--src", + nargs="?", + const="src", + metavar="DIR", + help="Upload DIR recursively to device root (:/, no leading directory). If DIR is omitted, uses local ./src." + ) + + parser.add_argument( + "--lib", + metavar="DIR", + help="Upload DIR recursively to /lib on device" + ) + parser.add_argument( "-e", dest="erase_all", @@ -410,9 +458,12 @@ Examples: if ran_reset: time.sleep(0.5) try: - print(f"Following output from {port}... (Press Ctrl+C to stop)", file=sys.stderr) + if value is None: + print(f"Following output from {port}... (Press Ctrl+C to stop)", file=sys.stderr) + else: + print(f"Following output from {port} for {value} seconds...", file=sys.stderr) conn = DeviceConnection(port) - conn.follow_output() + conn.follow_output(value) except KeyboardInterrupt: print("\nStopped following.", file=sys.stderr) sys.exit(0) @@ -421,10 +472,6 @@ Examples: sys.exit(1) return # follow blocks; when interrupted we're done - # If we ran any actions and follow wasn't last, we're done - if ordered_actions: - return - # Collect all edit parameters edits: Dict[str, Any] = {} @@ -450,7 +497,7 @@ Examples: edits["pattern"] = args.preset if args.default is not None: - edits["startup_preset"] = args.default + edits["default"] = args.default # 1. Download: get current settings from device try: diff --git a/device.py b/device.py index b935361..12312aa 100644 --- a/device.py +++ b/device.py @@ -208,12 +208,21 @@ class DeviceConnection: except Exception as e: raise TransportError(f"Failed to reset device: {e}") from e - def follow_output(self): - """Follow device output continuously (like tail -f).""" + def follow_output(self, duration=None): + """ + Follow device output (like tail -f). + + Args: + duration: Optional number of seconds to follow output for. If None, + follow indefinitely until interrupted. + """ # Use direct serial connection like dev.py does + start_time = time.time() try: with serial.Serial(self.device, baudrate=115200) as ser: while True: + if duration is not None and (time.time() - start_time) >= duration: + break if ser.in_waiting > 0: data = ser.readline().decode('utf-8', errors='replace').strip() if data: