Refactor monolith utils into domain modules and update docs

This commit is contained in:
zwitschi committed 2026-08-03 17:01:36 +02:00
1 parent 970e1b5eed
commit bbf07dec5a
11 files changed
+972 -54

No files matched your search

+84
View File
@@ -0,0 +1,84 @@
#!/usr/bin/env python3
"""Filesystem and I/O helpers for the intrusion-detection system."""
from __future__ import annotations
import csv
import gzip
import json
import os
import re
from typing import Any, Iterable, Iterator, Sequence
ANSI_RE = re.compile(r"\x1b\[[0-9;]*m")
# -- directory --------------------------------------------------------------
def validate_dir(path: str, need_write: bool = False) -> str:
if not os.path.exists(path):
raise FileNotFoundError(f"path does not exist: {path}")
if not os.path.isdir(path):
raise NotADirectoryError(f"path is not a directory: {path}")
if not os.access(path, os.R_OK):
raise PermissionError(f"path not readable: {path}")
if need_write and not os.access(path, os.W_OK):
raise PermissionError(f"path not writable: {path}")
return path
def ensure_dirs(*paths: str) -> None:
for p in paths:
os.makedirs(p, exist_ok=True)
# -- log discovery ----------------------------------------------------------
def find_logs(path: str, pattern: re.Pattern | None = None,
suffixes: Sequence[str] = (),
exclude_prefixes: Sequence[str] = ()) -> list[str]:
"""List matching log file names (not full paths), sorted."""
out = []
for name in os.listdir(path):
if not os.path.isfile(os.path.join(path, name)):
continue
if any(name.startswith(p) for p in exclude_prefixes):
continue
if pattern is not None and not pattern.match(name):
continue
if suffixes and not name.endswith(tuple(suffixes)):
continue
out.append(name)
return sorted(out)
def read_lines(path: str) -> Iterator[str]:
"""Yield ANSI-stripped, newline-stripped lines. Transparently gunzips."""
opener = gzip.open if path.endswith(".gz") else open
with opener(path, "rt", encoding="utf-8", errors="replace") as f:
for line in f:
yield ANSI_RE.sub("", line.rstrip("\r\n"))
# -- writers ----------------------------------------------------------------
def write_csv(path: str, header: Sequence[str],
rows: Iterable[Sequence[Any]]) -> str:
with open(path, "w", newline="", encoding="utf-8") as f:
w = csv.writer(f)
w.writerow(header)
w.writerows(rows)
return path
def write_json(path: str, obj: Any) -> str:
with open(path, "w", encoding="utf-8") as f:
json.dump(obj, f, indent=2, default=str)
return path
def write_lines(path: str, lines: Iterable[str]) -> str:
with open(path, "w", encoding="utf-8") as f:
for line in lines:
f.write(line + "\n")
return path