Enhance CLI actions and default handling

Add timed follow, src/lib upload helpers, and store default startup pattern under default key.

Made-with: Cursor
This commit is contained in:
2026-03-11 22:51:36 +13:00
parent 8df1d9dd81
commit d6ed6ad9f5
2 changed files with 70 additions and 14 deletions

71
cli.py
View File

@@ -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:

View File

@@ -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: