Coverage for src/bayernwerk_client/completion.py: 100%
39 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-17 13:07 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-17 13:07 +0000
1"""Shell completion for the `bayernwerk` CLI, powered by `argcomplete`.
3`bayernwerk completion <shell>` prints the activation snippet for that
4shell - generated on the fly from the actual argparse structure
5(`build_parser()`/`register()` in `cli.py` and the per-service `cli.py`
6modules), so it's always in sync with whatever commands actually exist.
7No hand-written/hardcoded completion script to keep updated.
9`bayernwerk completion install` writes an `eval "$(bayernwerk completion
10<shell>)"` line into the appropriate shell rc file (idempotent - checks
11for the marker comment first).
12"""
14from __future__ import annotations
16import argparse
17import os
18import sys
19from pathlib import Path
21import argcomplete
23_MARKER = "# bayernwerk shell completion"
24_EVAL_SHELL_RC_FILES = {
25 "bash": Path.home() / ".bashrc",
26 "zsh": Path.home() / ".zshrc",
27}
30def _detect_shell() -> str:
31 return Path(os.environ.get("SHELL", "/bin/bash")).name
34def cmd_bash(args: argparse.Namespace) -> None:
35 print(argcomplete.shellcode(["bayernwerk"], shell="bash"))
38def cmd_zsh(args: argparse.Namespace) -> None:
39 print(argcomplete.shellcode(["bayernwerk"], shell="zsh"))
42def cmd_fish(args: argparse.Namespace) -> None:
43 print(argcomplete.shellcode(["bayernwerk"], shell="fish"))
46def cmd_install(args: argparse.Namespace) -> None:
47 shell = args.shell or _detect_shell()
48 if shell not in _EVAL_SHELL_RC_FILES:
49 print(
50 f"Automatische Installation fuer '{shell}' wird nicht unterstuetzt (nur bash/zsh).\n"
51 f"Fuehre 'bayernwerk completion {shell}' aus und binde die Ausgabe manuell "
52 "in deine Shell-Konfiguration ein.",
53 file=sys.stderr,
54 )
55 raise SystemExit(1)
57 rc_path = _EVAL_SHELL_RC_FILES[shell]
58 existing = rc_path.read_text() if rc_path.exists() else ""
59 if _MARKER in existing:
60 print(f"Completion ist bereits in {rc_path} eingetragen.")
61 return
63 line = f'eval "$(bayernwerk completion {shell})"'
64 with rc_path.open("a") as f:
65 f.write(f"\n{_MARKER}\n{line}\n")
66 print(f"Completion-Zeile zu {rc_path} hinzugefuegt. Neue Shell starten oder 'source {rc_path}' ausfuehren.")
69def register(subparsers: argparse._SubParsersAction) -> None:
70 """Add the `completion` command (and its own sub-subcommands) to `subparsers`."""
71 comp_parser = subparsers.add_parser("completion", help="Shell-Autovervollstaendigung generieren/installieren")
72 comp_sub = comp_parser.add_subparsers(dest="completion_command", required=True)
74 comp_sub.add_parser(
75 "bash", help="Bash-Completion-Skript ausgeben", description="Bash-Completion-Skript ausgeben"
76 ).set_defaults(func=cmd_bash)
77 comp_sub.add_parser(
78 "zsh", help="Zsh-Completion-Skript ausgeben", description="Zsh-Completion-Skript ausgeben"
79 ).set_defaults(func=cmd_zsh)
80 comp_sub.add_parser(
81 "fish", help="Fish-Completion-Skript ausgeben", description="Fish-Completion-Skript ausgeben"
82 ).set_defaults(func=cmd_fish)
84 p = comp_sub.add_parser(
85 "install",
86 help="Completion automatisch in die Shell-Konfiguration eintragen (bash/zsh)",
87 description="Completion automatisch in die Shell-Konfiguration eintragen (bash/zsh)",
88 )
89 p.add_argument("--shell", choices=["bash", "zsh"], help="Shell explizit angeben (Default: aus $SHELL erkannt)")
90 p.set_defaults(func=cmd_install)