jw-pkg/src/python/jw/pkg/lib/ExecApp.py

87 lines
2.9 KiB
Python
Raw Normal View History

from __future__ import annotations
import sys
from typing import TYPE_CHECKING, Any, override
from .App import App as Base
if TYPE_CHECKING:
from argparse import ArgumentParser
from .ExecContext import ExecContext
class ExecApp(Base): # export
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
self.__opt_interactive: bool | None = None
self.__opt_verbose: bool | None = None
self.__exec_context: ExecContext | None = None
@override
async def __aexit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
if self.__exec_context is not None:
await self.__exec_context.close()
self.__exec_context = None
# -- Close the app (async runner, event loop) after the exec context,
# which may still need them.
await super().__aexit__(exc_type, exc, tb)
@override
def _add_arguments(self, parser: ArgumentParser) -> None:
super()._add_arguments(parser)
parser.add_argument(
'--interactive',
choices = ['true', 'false', 'auto'],
default = 'true',
help = 'Wait for user input or try to proceed unattended',
)
parser.add_argument(
'--verbose',
action = 'store_true',
default = False,
help = "Be verbose on stderr about what's being done on the distro level",
)
parser.add_argument(
'--target', default = 'local', help = 'Run commands on this host'
)
@property
def interactive(self) -> bool:
if self.__opt_interactive is None:
match self.args.interactive:
case 'true':
self.__opt_interactive = True
case 'false':
self.__opt_interactive = False
case 'auto':
self.__opt_interactive = sys.stdin.isatty()
case _:
raise ValueError(
f'Unknown --interactive value: {self.args.interactive}'
)
# Not logically possible to fail, but this keeps pyright happy
assert self.__opt_interactive is not None
return self.__opt_interactive
@property
def verbose(self) -> bool:
if self.__opt_verbose is None:
self.__opt_verbose = self.args.verbose
# Not logically possible to fail, but this keeps pyright happy
assert self.__opt_verbose is not None
return self.__opt_verbose
@property
def exec_context(self) -> ExecContext:
if self.__exec_context is None:
from .ExecContext import ExecContext
self.__exec_context = ExecContext.create(
self.args.target,
interactive = self.interactive,
verbose_default = self.verbose,
)
return self.__exec_context