diff options
Diffstat (limited to '')
| -rw-r--r-- | prometheus_pacman_exporter/cli.py | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/prometheus_pacman_exporter/cli.py b/prometheus_pacman_exporter/cli.py new file mode 100644 index 0000000..5d91b05 --- /dev/null +++ b/prometheus_pacman_exporter/cli.py @@ -0,0 +1,161 @@ +# SPDX-FileCopyrightText: 2026 Dennis Fink <me+coding@dennisfink.me> +# +# SPDX-License-Identifier: BSD-3-Clause + +"""Define Click parameter types and styled terminal message helpers.""" + +from collections.abc import Callable +from functools import update_wrapper +from typing import Any, Concatenate + +import click_extra as click + + +class FlexibleColorOption(click.ColorOption): + """Allow the color option value to be passed with or without ``=``.""" + + _gnu_optional_value = False + + +def pass_obj_silent[T, **P, R]( + f: Callable[Concatenate[T | None, P], R], +) -> Callable[P, R]: + """Pass the current context object to a callback, if available. + + The current Click context is retrieved silently. If no context exists or + its object is not a dictionary, ``None`` is passed instead. + + The context object is inserted as the first positional argument to *f*. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + ctx = click.get_current_context(silent=True) + obj = ctx.obj if ctx is not None else None + return f(obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + +def emit( + prefix: str, color: str, *message: str, enabled: bool = True, err: bool = False +) -> None: + """Render a styled prefix and message to stdout. + + This helper is used by :func:`error`, :func:`msg`, :func:`warn`, + :func:`verbose`, and :func:`debug`. The first message argument is rendered in + bold and subsequent arguments are appended unstyled. + + :param prefix: Prefix displayed before the message. + :param color: Click-compatible color name applied to the prefix. + :param message: One or more message parts to display. + :param enabled: Whether the message should be emitted. + :param err: Write to `stderr` instead of `stdout`. + :raises TypeError: If no message arguments are provided. + """ + if not message: + raise TypeError("emit() missing 1 required positional argument: 'message'") + + if not enabled: + return + + click.echo( + " ".join( + [ + click.style(prefix, fg=color, bold=True), + click.style(message[0], bold=True), + *message[1:], + ] + ), + err=err, + ) + + +def error(*message: str) -> None: + """Print a formatted error message to stdout in red. + + The first argument is rendered in bold and subsequent arguments are appended + unstyled. Error messages are always printed regardless of quiet or verbose + flags. + + :param message: One or more message parts to display. + """ + emit("==> ERROR:", "red", *message, err=True) + + +@pass_obj_silent +def msg(obj: dict[str, Any] | None, *message: str, err: bool = False) -> None: + """Print a formatted informational message to stdout in green. + + The message is suppressed when the quiet flag is set. When called outside a + Click context, the message is emitted normally. The first argument is rendered + in bold and subsequent arguments are appended unstyled. + + :param message: One or more message parts to display. + """ + emit( + "==>", + "green", + *message, + enabled=obj is None or not obj.get("quiet", False), + err=err, + ) + + +@pass_obj_silent +def warn(obj: dict[str, Any] | None, *message: str, err: bool = False) -> None: + """Print a formatted warning message to stdout in yellow. + + The message is suppressed when the quiet flag is set. When called outside a + Click context, the message is emitted normally. The first argument is rendered + in bold and subsequent arguments are appended unstyled. + + :param message: One or more message parts to display. + """ + emit( + "==>", + "yellow", + *message, + enabled=obj is None or not obj.get("quiet", False), + err=err, + ) + + +@pass_obj_silent +def verbose(obj: dict[str, Any] | None, *message: str, err: bool = False) -> None: + """Print a formatted verbose message to stdout in blue. + + The message is printed only when called from a Click context with the verbose + flag set and the quiet flag unset. Calls made outside a Click context are a + no-op. + + :param message: One or more message parts to display. + """ + emit( + "==>", + "blue", + *message, + enabled=( + obj is not None + and obj.get("verbose", False) + and not obj.get("quiet", False) + ), + err=err, + ) + + +@pass_obj_silent +def debug(obj: dict[str, Any] | None, *message: str, err: bool = False) -> None: + """Print a formatted debug message to stdout in magenta. + + The message is printed only when called from a Click context with the debug + flag enabled. Calls made outside a Click context are a no-op. + + :param message: One or more message parts to display. + """ + emit( + "==>", + "magenta", + *message, + enabled=obj is not None and obj.get("debug", False), + err=err, + ) |
