diff options
| author | Dennis Fink | 2026-09-27 15:19:59 +0200 |
|---|---|---|
| committer | Dennis Fink | 2026-09-27 15:21:53 +0200 |
| commit | a9934b8a44ccd6f482e7399f931412e8b43033f4 (patch) | |
| tree | a07bb151d120161f9f69fcddde9cb9531cc22478 /prometheus_pacman_exporter/__init__.py | |
| parent | f898ed214f19155b842a537756a22c6dcc64b379 (diff) | |
| download | prometheus-pacman-exporter-a9934b8a44ccd6f482e7399f931412e8b43033f4.tar.gz prometheus-pacman-exporter-a9934b8a44ccd6f482e7399f931412e8b43033f4.zip | |
refactor(commands): model package queries explicitly
Introduce a PackageQuery type to group each command with its
description, metric, and accepted exit codes.
Move the static pacman queries into module-level constants and construct
only the update and optional AUR queries at runtime.
Use immutable command tuples throughout and rename success_codes to
accepted_exit_codes to better describe the command execution contract.
Diffstat (limited to 'prometheus_pacman_exporter/__init__.py')
| -rw-r--r-- | prometheus_pacman_exporter/__init__.py | 139 |
1 files changed, 74 insertions, 65 deletions
diff --git a/prometheus_pacman_exporter/__init__.py b/prometheus_pacman_exporter/__init__.py index cb19032..73f0945 100644 --- a/prometheus_pacman_exporter/__init__.py +++ b/prometheus_pacman_exporter/__init__.py @@ -8,11 +8,11 @@ import os import shlex import subprocess from pathlib import Path -from typing import cast +from typing import NamedTuple, cast import click_extra as click from cloup.constraints import If, require_all -from prometheus_client import write_to_textfile +from prometheus_client import Gauge, write_to_textfile from . import metrics from .cli import FlexibleColorOption, debug, error, msg, verbose @@ -25,6 +25,47 @@ AUTHOR = "Dennis Fink <me+coding@dennisfink.me>" LICENSE = "BSD-3-Clause" +class PackageQuery(NamedTuple): + command: tuple[str, ...] + description: str + metric: Gauge + accepted_exit_codes: tuple[int, ...] = (0,) + + +PACMAN_BASE_COMMAND = ("pacman", "--query") +BASE_QUERIES: tuple[PackageQuery, ...] = ( + PackageQuery(PACMAN_BASE_COMMAND, "installed packages", metrics.INSTALLED_PACKAGES), + PackageQuery( + (*PACMAN_BASE_COMMAND, "--explicit"), + "explicitly installed packages", + metrics.EXPLICIT_PACKAGES, + ), + PackageQuery( + (*PACMAN_BASE_COMMAND, "--deps"), + "packages installed as dependencies", + metrics.DEPENDS_PACKAGES, + ), + PackageQuery( + (*PACMAN_BASE_COMMAND, "--unrequired"), + "unrequired packages", + metrics.UNREQUIRED_PACKAGES, + ), + PackageQuery( + (*PACMAN_BASE_COMMAND, "--foreign"), + "foreign packages", + metrics.FOREIGN_PACKAGES, + ), + PackageQuery( + (*PACMAN_BASE_COMMAND, "--native"), "native packages", metrics.NATIVE_PACKAGES + ), + PackageQuery( + (*PACMAN_BASE_COMMAND, "--deps", "--unrequired"), + "orphan packages", + metrics.ORPHAN_PACKAGES, + ), +) + + def print_version( ctx: click.Context, param: click.Parameter | None, value: bool ) -> None: @@ -80,7 +121,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.""") @click.pass_context def run_command( - ctx: click.Context, command: list[str], success_codes: tuple[int, ...] = (0,) + ctx: click.Context, + command: tuple[str, ...], + accepted_exit_codes: tuple[int, ...] = (0,), ) -> subprocess.CompletedProcess[str]: """Run a shell command and return the result. @@ -89,13 +132,13 @@ def run_command( :param ctx: Click context injected by :func:`click.pass_context`. :param command: Command and its arguments. - :param success_codes: Exit codes considered successful. + :param accepted_exit_codes: Exit codes considered successful. :return: Completed process with stdout and stderr captured. """ debug("Running command", " ".join(command), err=True) result = subprocess.run(command, capture_output=True, encoding="utf-8", check=False) - if result.returncode not in success_codes: + if result.returncode not in accepted_exit_codes: error( f"Command ({' '.join(command)}) failed with exit code {result.returncode}" ) @@ -201,75 +244,41 @@ def prometheus_pacman_exporter( debug(" verbose:", str(verbose_flag), err=True) debug(" quiet:", str(quiet_flag), err=True) - pacman_base_command = ["pacman", "--query"] - queries = [ - ( - [*pacman_base_command], - "installed packages", - metrics.INSTALLED_PACKAGES, - (0,), - ), - ( - [*pacman_base_command, "--explicit"], - "explicitly installed packages", - metrics.EXPLICIT_PACKAGES, - (0,), - ), - ( - [*pacman_base_command, "--deps"], - "packages installed as dependencies", - metrics.DEPENDS_PACKAGES, - (0,), - ), - ( - [*pacman_base_command, "--unrequired"], - "unrequired packages", - metrics.UNREQUIRED_PACKAGES, - (0,), - ), - ( - [*pacman_base_command, "--foreign"], - "foreign packages", - metrics.FOREIGN_PACKAGES, - (0,), - ), - ( - [*pacman_base_command, "--native"], - "native packages", - metrics.NATIVE_PACKAGES, - (0,), - ), - ( - [*pacman_base_command, "--deps", "--unrequired"], - "orphan packages", - metrics.ORPHAN_PACKAGES, - (0,), - ), - ( - ["checkupdates"] - if use_checkupdates_flag - else [*pacman_base_command, "--upgrades"], - "updateable packages", - metrics.UPDATEABLE_PACKAGES, - (0, 2) if use_checkupdates_flag else (0, 1), - ), - ] + queries: list[PackageQuery] = [*BASE_QUERIES] + + if use_checkupdates_flag: + queries.append( + PackageQuery( + ("checkupdates",), + "updateable packages", + metrics.UPDATEABLE_PACKAGES, + (0, 2), + ) + ) + else: + queries.append( + PackageQuery( + (*PACMAN_BASE_COMMAND, "--upgrades"), + "updateable packages", + metrics.UPDATEABLE_PACKAGES, + (0, 1), + ) + ) if aur_flag: queries.append( - ( - shlex.split(cast(str, aur_command)), + PackageQuery( + tuple(shlex.split(cast(str, aur_command))), "AUR updateable packages", metrics.AUR_UPDATEABLE_PACKAGES, - (0,), ) ) - for command, description, metric, success_codes in queries: - output = run_command(command, success_codes) + for query in queries: + output = run_command(query.command, query.accepted_exit_codes) value = len(output.stdout.splitlines()) - verbose(f"Setting {description}:", str(value), err=True) - metric.set(value) + verbose(f"Setting {query.description}:", str(value), err=True) + query.metric.set(value) metrics_file = textfile_collector_dir / "pacman.prom" write_to_textfile(str(metrics_file.absolute()), metrics.REGISTRY) |
