Default interactive CLI to menu
This commit is contained in:
@@ -46,6 +46,8 @@ Guidance for coding agents working in this repo.
|
|||||||
- Be careful with duplicate instance names across Windows and local roots. Use
|
- Be careful with duplicate instance names across Windows and local roots. Use
|
||||||
the menu or pass `--instances-root` explicitly when targeting one install, and
|
the menu or pass `--instances-root` explicitly when targeting one install, and
|
||||||
keep install/bootstrap state separate per target root.
|
keep install/bootstrap state separate per target root.
|
||||||
|
- After completing repo changes, suggest a concise commit message in the final
|
||||||
|
response unless the user already asked you to commit.
|
||||||
|
|
||||||
## Validation
|
## Validation
|
||||||
|
|
||||||
|
|||||||
@@ -66,9 +66,12 @@ backups, and installed file records for different game trees.
|
|||||||
For normal use, run the Textual menu from the repo root:
|
For normal use, run the Textual menu from the repo root:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
PYTHONPATH=src python -m plugin_helper menu
|
PYTHONPATH=src python -m plugin_helper
|
||||||
```
|
```
|
||||||
|
|
||||||
|
That is equivalent to `PYTHONPATH=src python -m plugin_helper menu` when run
|
||||||
|
from an interactive terminal.
|
||||||
|
|
||||||
The menu reads `plugin-helper.local.toml` when present, shows each discovered
|
The menu reads `plugin-helper.local.toml` when present, shows each discovered
|
||||||
Beat Saber install with its resolved state directory, and lets you toggle
|
Beat Saber install with its resolved state directory, and lets you toggle
|
||||||
managed plugins with arrow keys and Space. In the plugin table, use `d` to
|
managed plugins with arrow keys and Space. In the plugin table, use `d` to
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ def _add_common(parser: argparse.ArgumentParser, *, suppress_default: bool = Fal
|
|||||||
def build_parser() -> argparse.ArgumentParser:
|
def build_parser() -> argparse.ArgumentParser:
|
||||||
parser = argparse.ArgumentParser(prog="plugin-helper")
|
parser = argparse.ArgumentParser(prog="plugin-helper")
|
||||||
_add_common(parser)
|
_add_common(parser)
|
||||||
subcommands = parser.add_subparsers(dest="command", required=True)
|
subcommands = parser.add_subparsers(dest="command")
|
||||||
|
|
||||||
subcommands.add_parser(
|
subcommands.add_parser(
|
||||||
"instances",
|
"instances",
|
||||||
@@ -309,6 +309,13 @@ def run(argv: list[str] | None = None) -> int:
|
|||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if args.command is None:
|
||||||
|
if sys.stdin.isatty() and sys.stdout.isatty():
|
||||||
|
args.command = "menu"
|
||||||
|
else:
|
||||||
|
parser.print_help()
|
||||||
|
return 2
|
||||||
|
|
||||||
explicit_instances_root = getattr(args, "instances_root", None) is not None
|
explicit_instances_root = getattr(args, "instances_root", None) is not None
|
||||||
explicit_state_dir = getattr(args, "state_dir", None) is not None
|
explicit_state_dir = getattr(args, "state_dir", None) is not None
|
||||||
runtime = resolve_runtime_config(
|
runtime = resolve_runtime_config(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import json
|
|||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
import os
|
import os
|
||||||
|
from io import StringIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
@@ -180,6 +181,26 @@ state_dir = ".state"
|
|||||||
self.assertEqual(runtime.state_root, root / "explicit-state")
|
self.assertEqual(runtime.state_root, root / "explicit-state")
|
||||||
self.assertEqual(runtime.selected_profile.id, "linux")
|
self.assertEqual(runtime.selected_profile.id, "linux")
|
||||||
|
|
||||||
|
def test_no_args_prints_help_when_not_interactive(self) -> None:
|
||||||
|
output = StringIO()
|
||||||
|
with patch("sys.stdin.isatty", return_value=False), patch("sys.stdout", output):
|
||||||
|
status = run([])
|
||||||
|
|
||||||
|
self.assertEqual(status, 2)
|
||||||
|
self.assertIn("usage: plugin-helper", output.getvalue())
|
||||||
|
self.assertIn("menu", output.getvalue())
|
||||||
|
|
||||||
|
def test_no_command_defaults_to_menu_when_interactive(self) -> None:
|
||||||
|
with (
|
||||||
|
patch("sys.stdin.isatty", return_value=True),
|
||||||
|
patch("sys.stdout.isatty", return_value=True),
|
||||||
|
patch("plugin_helper.cli._run_menu", return_value=0) as run_menu,
|
||||||
|
):
|
||||||
|
status = run(["--profile", "linux"])
|
||||||
|
|
||||||
|
self.assertEqual(status, 0)
|
||||||
|
run_menu.assert_called_once()
|
||||||
|
|
||||||
def test_run_ipa_timeout_returns_control(self) -> None:
|
def test_run_ipa_timeout_returns_control(self) -> None:
|
||||||
with tempfile.TemporaryDirectory() as tmp:
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
result = _run_ipa(
|
result = _run_ipa(
|
||||||
|
|||||||
Reference in New Issue
Block a user