1import gettext
2import logging
3from typing import Any, Callable, TypeVar
4
5import click
6
7from suricata_check._version import get_version
8
9_AnyCallable = Callable[..., Any]
10FC = TypeVar("FC", bound="_AnyCallable | click.Command")
11
12
13def help_option(*param_decls: str, **kwargs: dict[str, Any]) -> Callable[[FC], FC]:
14 """``--help`` option which immediately printsversion help info and exits.
15
16 :param param_decls: One or more option names. Defaults to the single
17 value ``"--help"``.
18 :param kwargs: Extra arguments are passed to :func:`option`.
19 """
20
21 def show_help(
22 ctx: click.Context, param: click.Parameter, value: bool # noqa: ARG001
23 ) -> None:
24 """Callback that print the help page on ``<stdout>`` and exits."""
25 click.echo("suricata-check {}\n".format(get_version()))
26
27 if value and not ctx.resilient_parsing:
28 click.echo(ctx.get_help(), color=ctx.color)
29 ctx.exit()
30
31 if not param_decls:
32 param_decls = ("--help",)
33
34 kwargs.setdefault("is_flag", True) # pyright: ignore[reportArgumentType]
35 kwargs.setdefault("expose_value", False) # pyright: ignore[reportArgumentType]
36 kwargs.setdefault("is_eager", True) # pyright: ignore[reportArgumentType]
37 kwargs.setdefault(
38 "help",
39 gettext.gettext(
40 "Show this message and exit."
41 ), # pyright: ignore[reportArgumentType]
42 )
43 kwargs.setdefault("callback", show_help) # pyright: ignore[reportArgumentType]
44
45 return click.option(*param_decls, **kwargs) # pyright: ignore[reportArgumentType]
46
47
[docs]
48class ClickHandler(logging.Handler):
49 """Handler to color and write logging messages for the click module."""
50
51 def __init__(
52 self: "ClickHandler",
53 level: int = 0,
54 github: bool = False,
55 github_level: int = logging.WARNING,
56 **kwargs: dict,
57 ) -> None:
58 super().__init__(level, **kwargs)
59 self.github = github
60 self.github_level = github_level
61
[docs]
62 def emit(self: "ClickHandler", record: logging.LogRecord) -> None:
63 """Log the record via click stdout with appropriate colors."""
64 msg = self.format(record)
65
66 if logging.getLevelName(record.levelno) == "DEBUG":
67 click.secho(msg, color=True, dim=True)
68 if logging.getLevelName(record.levelno) == "INFO":
69 click.secho(msg, color=True)
70 if logging.getLevelName(record.levelno) == "WARNING":
71 click.secho(msg, color=True, bold=True, fg="yellow")
72 if logging.getLevelName(record.levelno) == "ERROR":
73 click.secho(msg, color=True, bold=True, fg="red")
74 if logging.getLevelName(record.levelno) == "CRITICAL":
75 click.secho(msg, color=True, bold=True, blink=True, fg="red")
76
77 if self.github and record.levelno >= self.github_level:
78 print(f"::debug::{msg}") # noqa: T201