diff options
author | Marc-André Lureau <marcandre.lureau@redhat.com> | 2025-09-02 13:31:10 +0400 |
---|---|---|
committer | Marc-André Lureau <marcandre.lureau@redhat.com> | 2025-09-03 16:18:12 +0400 |
commit | 402651d98f1a3635ee22b005cb4b4be15004daf0 (patch) | |
tree | 0b1529a23a2325c8a7b07c94ef51a8495c0efa24 | |
parent | a6f5d50239a64a26266a744f86ad2591e12c5fec (diff) | |
download | libvirt-ci-master.zip libvirt-ci-master.tar.gz libvirt-ci-master.tar.bz2 |
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
-rw-r--r-- | lcitool/__main__.py | 7 | ||||
-rw-r--r-- | lcitool/ansible_wrapper.py | 2 | ||||
-rw-r--r-- | lcitool/application.py | 77 | ||||
-rw-r--r-- | lcitool/commandline.py | 37 | ||||
-rw-r--r-- | pyproject.toml | 15 |
5 files changed, 79 insertions, 59 deletions
diff --git a/lcitool/__main__.py b/lcitool/__main__.py index 99297a3..284eb4e 100644 --- a/lcitool/__main__.py +++ b/lcitool/__main__.py @@ -1,5 +1,6 @@ import sys import logging +from typing import Any from lcitool.application import Application from lcitool.commandline import CommandLine @@ -7,11 +8,11 @@ from lcitool.logger import LevelFormatter class LcitoolLogger(logging.Logger): - def debug(self, *args, **kwargs): + def debug(self, *args: Any, **kwargs: Any) -> None: super().debug(*args, **kwargs, exc_info=True) -def main(): +def main() -> None: log_level_formats = { logging.DEBUG: "[%(levelname)s] %(module)s:%(funcName)s:%(lineno)d: %(message)s", logging.INFO: "[%(levelname)s]: %(message)s", @@ -40,4 +41,4 @@ def main(): if __name__ == "__main__": - sys.exit(main()) + main() diff --git a/lcitool/ansible_wrapper.py b/lcitool/ansible_wrapper.py index 8b5a01c..21e5c46 100644 --- a/lcitool/ansible_wrapper.py +++ b/lcitool/ansible_wrapper.py @@ -86,7 +86,7 @@ class AnsibleWrapper: Any, ] ] = None, - extravars: None = None, + extravars: Optional[Dict[str, Any]] = None, ) -> None: """ Prepares the Ansible runner execution environment. diff --git a/lcitool/application.py b/lcitool/application.py index f65fc3f..1b76d0c 100644 --- a/lcitool/application.py +++ b/lcitool/application.py @@ -7,12 +7,15 @@ import logging import sys import textwrap +from typing import Any, Callable, Dict, Optional, Union +import argparse from pathlib import Path from tempfile import TemporaryDirectory, NamedTemporaryFile from lcitool import util, LcitoolError from lcitool.config import Config +from lcitool.util import DataDir from lcitool.inventory import Inventory from lcitool.packages import Packages from lcitool.projects import Projects @@ -26,14 +29,15 @@ from lcitool.formatters import ( from lcitool.formatters import ShellBuildEnvFormatter from lcitool.manifest import Manifest from lcitool.containers import Docker, Podman, ContainerExecError +from lcitool.containers.containers import Container log = logging.getLogger(__name__) -def required_deps(*deps): - def inner_decorator(func): - def wrapped(*args, **kwargs): +def required_deps(*deps: str) -> Callable: + def inner_decorator(func: Callable) -> Callable: + def wrapped(*args: Any, **kwargs: Any) -> Any: cmd = func.__name__[len("_action_") :] for dep in deps: try: @@ -52,18 +56,18 @@ def required_deps(*deps): class ApplicationError(LcitoolError): - def __init__(self, message): + def __init__(self, message: str) -> None: super().__init__(message, "Application") class Application: - def __init__(self): + def __init__(self) -> None: # make sure the lcitool cache dir exists cache_dir_path = util.get_cache_dir() cache_dir_path.mkdir(parents=True, exist_ok=True) @staticmethod - def _entrypoint_debug(args): + def _entrypoint_debug(args: argparse.Namespace) -> None: cli_args = {} for arg, val in vars(args).items(): if arg not in ["func", "debug"]: @@ -71,8 +75,14 @@ class Application: log.debug(f"Cmdline args={cli_args}") def _execute_playbook( - self, playbook, hosts_pattern, projects_pattern, config, data_dir, verbosity=0 - ): + self, + playbook: str, + hosts_pattern: str, + projects_pattern: str, + config_path: Optional[Path], + data_dir: DataDir, + verbosity: int = 0, + ) -> None: from lcitool.ansible_wrapper import AnsibleWrapper log.debug( @@ -82,7 +92,7 @@ class Application: ) base = util.package_resource(__package__, "ansible").as_posix() - config = Config(config) + config = Config(config_path) targets = Targets(data_dir) packages = Packages(data_dir) projects = Projects(data_dir) @@ -98,12 +108,14 @@ class Application: user_pre = False if data_dir: + assert data_dir.path ansible_path = Path(data_dir.path, "ansible") if ansible_path.exists(): if Path(ansible_path, "pre/tasks/main.yml").exists(): user_pre = True - extra_vars = config.values + extra_vars: Dict[str, Any] = {} + extra_vars.update(config.values) extra_vars.update( { "base": base, @@ -130,7 +142,7 @@ class Application: ) ansible_runner.prepare_env( - playbookdir=playbook_base, + playbookdir=None, inventories=[inventory.ansible_inventory], group_vars=group_vars, extravars=extra_vars, @@ -139,7 +151,7 @@ class Application: ansible_runner.run_playbook(limit=hosts_expanded, verbosity=verbosity) @required_deps("ansible_runner", "libvirt") - def _action_hosts(self, args): + def _action_hosts(self, args: argparse.Namespace) -> None: self._entrypoint_debug(args) config_path = None @@ -154,7 +166,7 @@ class Application: for host in sorted(inventory.hosts): print(host) - def _action_targets(self, args): + def _action_targets(self, args: argparse.Namespace) -> None: self._entrypoint_debug(args) targets = Targets(args.data_dir) @@ -167,7 +179,7 @@ class Application: print(target) - def _action_projects(self, args): + def _action_projects(self, args: argparse.Namespace) -> None: self._entrypoint_debug(args) projects = Projects(args.data_dir) @@ -175,7 +187,7 @@ class Application: print(project) @required_deps("libvirt") - def _action_install(self, args): + def _action_install(self, args: argparse.Namespace) -> None: from lcitool.install import VirtInstall self._entrypoint_debug(args) @@ -230,7 +242,7 @@ class Application: virt_install(wait=args.wait) @required_deps("ansible_runner", "libvirt") - def _action_update(self, args): + def _action_update(self, args: argparse.Namespace) -> None: self._entrypoint_debug(args) config_path = None @@ -246,7 +258,7 @@ class Application: args.verbose, ) - def _action_variables(self, args): + def _action_variables(self, args: argparse.Namespace) -> None: self._entrypoint_debug(args) targets = Targets(args.data_dir) @@ -254,6 +266,9 @@ class Application: projects = Projects(args.data_dir) projects_expanded = projects.expand_names(args.projects) + formatter: Union[ + ShellVariablesFormatter, YamlVariablesFormatter, JSONVariablesFormatter + ] if args.format == "shell": formatter = ShellVariablesFormatter(projects) elif args.format == "yaml": @@ -280,7 +295,7 @@ class Application: print(header + variables) - def _action_dockerfile(self, args): + def _action_dockerfile(self, args: argparse.Namespace) -> None: self._entrypoint_debug(args) targets = Targets(args.data_dir) @@ -308,7 +323,7 @@ class Application: print(header + dockerfile) - def _action_buildenvscript(self, args): + def _action_buildenvscript(self, args: argparse.Namespace) -> None: self._entrypoint_debug(args) targets = Targets(args.data_dir) @@ -333,7 +348,7 @@ class Application: print(header + buildenvscript) - def _action_manifest(self, args): + def _action_manifest(self, args: argparse.Namespace) -> None: base_path = None if args.base_dir is not None: base_path = Path(args.base_dir) @@ -347,8 +362,8 @@ class Application: manifest.generate(args.dry_run) @staticmethod - def _container_handle(engine): - handle = Podman() + def _container_handle(engine: str) -> Container: + handle: Container = Podman() if engine == "docker": handle = Docker() @@ -357,7 +372,7 @@ class Application: return handle - def _action_list_engines(self, args): + def _action_list_engines(self, args: argparse.Namespace) -> None: engines = [] for engine in [Podman(), Docker()]: if engine.available: @@ -368,7 +383,7 @@ class Application: else: print("No engine available") - def _action_container_build(self, args): + def _action_container_build(self, args: argparse.Namespace) -> None: self._entrypoint_debug(args) targets = Targets() @@ -397,12 +412,12 @@ class Application: log.debug(f"Generated Dockerfile copied to {_file}") - engine.build(tag=tag, filepath=_file, **params) + engine.build(tag=tag, filepath=Path(_file), tempdir=Path(params["tempdir"])) log.debug(f"Generated image tag --> {tag}") print(f"Image '{tag}' successfully built.") - def _get_container_run_common_params(self): + def _get_container_run_common_params(self) -> Dict[str, Any]: params = {} params["image"] = self.args.image params["user"] = self.args.user @@ -426,7 +441,9 @@ class Application: return params - def _container_run(self, container_params, shell=False): + def _container_run( + self, container_params: Dict[str, Any], shell: bool = False + ) -> int: """ Call into the container handle object. @@ -444,19 +461,19 @@ class Application: return engine.shell(**container_params) return engine.run(**container_params) - def _action_container_run(self, args): + def _action_container_run(self, args: argparse.Namespace) -> int: self._entrypoint_debug(self.args) params = self._get_container_run_common_params() params["container_cmd"] = "./script" return self._container_run(params) - def _action_container_shell(self, args): + def _action_container_shell(self, args: argparse.Namespace) -> int: self._entrypoint_debug(self.args) return self._container_run(self._get_container_run_common_params(), shell=True) - def run(self, args): + def run(self, args: argparse.Namespace) -> None: try: self.args = args args.func(self, args) diff --git a/lcitool/commandline.py b/lcitool/commandline.py index fe58971..fc02c52 100644 --- a/lcitool/commandline.py +++ b/lcitool/commandline.py @@ -7,6 +7,7 @@ import sys import logging import argparse +from typing import Any, List, Optional from pathlib import Path @@ -19,18 +20,34 @@ log = logging.getLogger(__name__) class DataDirAction(argparse.Action): - def __init__(self, option_strings, dest, default=DataDir(), nargs=None, **kwargs): + def __init__( + self, + option_strings: List[str], + dest: str, + default: DataDir = DataDir(), + nargs: Optional[Any] = None, + **kwargs: Any, + ) -> None: if nargs is not None: raise ValueError("nargs not allowed") super().__init__(option_strings, dest, default=default, nargs=1, **kwargs) - def __call__(self, parser, namespace, values, option_string=None): - setattr(namespace, self.dest, DataDir(values[0])) + def __call__( + self, + parser: argparse.ArgumentParser, + namespace: argparse.Namespace, + values: Any, + option_string: Optional[str] = None, + ) -> None: + if isinstance(values, (list, tuple)) and values: + setattr(namespace, self.dest, DataDir(Path(str(values[0])))) + elif isinstance(values, str): + setattr(namespace, self.dest, DataDir(Path(values))) class CommandLine: - def __init__(self): + def __init__(self) -> None: # Common option parsers to inherit from hostsopt = argparse.ArgumentParser(add_help=False) @@ -391,7 +408,7 @@ class CommandLine: shell_containerparser.set_defaults(func=Application._action_container_shell) @staticmethod - def _validate_container(args): + def _validate_container(args: argparse.Namespace) -> None: if args.container not in ["build", "run", "shell"]: return @@ -399,7 +416,7 @@ class CommandLine: # "build" subcommand. if args.container == "build": if args.projects and args.target: - return args + pass else: log.error("--target and --projects are required") sys.exit(1) @@ -412,16 +429,14 @@ class CommandLine: sys.exit(1) @staticmethod - def _validate_install(args): + def _validate_install(args: argparse.Namespace) -> None: if args.strategy == "template": if not args.template: log.error("--template is required with with --strategy=template") sys.exit(1) - return - # Main CLI validating method - def _validate(self, args): + def _validate(self, args: argparse.Namespace) -> argparse.Namespace: """ Validate command line arguments. :param args: argparse.Namespace object which contains @@ -438,5 +453,5 @@ class CommandLine: return args - def parse(self): + def parse(self) -> argparse.Namespace: return self._validate(self._parser.parse_args()) diff --git a/pyproject.toml b/pyproject.toml index 47d0131..a3a81de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,20 +65,7 @@ warn_return_any = true warn_unused_configs = true disallow_untyped_defs = true files = [ - "lcitool/__init__.py", - "lcitool/ansible_wrapper.py", - "lcitool/config.py", - "lcitool/containers/*.py", - "lcitool/install/*.py", - "lcitool/formatters.py", - "lcitool/gitlab.py", - "lcitool/inventory.py", - "lcitool/libvirt_wrapper.py", - "lcitool/logger.py", - "lcitool/manifest.py", - "lcitool/projects.py", - "lcitool/targets.py", - "lcitool/util.py", + "lcitool/", ] [[tool.mypy.overrides]] |