Files
git-automatic-tracker-py/src/git_auto_tracker/audit.py
T
2026-09-12 09:01:14 +02:00

46 lines
1.4 KiB
Python

"""ULID generation (Section 35).
ULIDs are lexicographically sortable, timezone-independent identifiers
linking logs, commits and monitoring. Implemented without an external
dependency per the specification's "equivalent identifier" allowance.
"""
from __future__ import annotations
import datetime as dt
import secrets
_ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ" # Crockford base32
_RANDOM_LEN = 16
_TIME_LEN = 10
def _encode_time(timestamp_ms: int) -> str:
value = max(timestamp_ms, 0)
chars = [""] * _TIME_LEN
for i in range(_TIME_LEN - 1, -1, -1):
chars[i] = _ENCODING[value & 0x1F]
value >>= 5
return "".join(chars)
def _encode_random(count: int) -> str:
# 5 bits per char; gather enough random bytes then fold
bits = count * 5
nbytes = (bits + 7) // 8
raw = int.from_bytes(secrets.token_bytes(nbytes), "big")
chars = [""] * count
for i in range(count - 1, -1, -1):
chars[i] = _ENCODING[raw & 0x1F]
raw >>= 5
return "".join(chars)
def new_ulid(timestamp: dt.datetime | None = None) -> str:
"""Generate a ULID string, e.g. 01J7K8HYV84ZKFH1J4T9R8DZQN."""
moment = timestamp or dt.datetime.now(dt.UTC)
if moment.tzinfo is None:
moment = moment.replace(tzinfo=dt.UTC)
timestamp_ms = int(moment.timestamp() * 1000)
return _encode_time(timestamp_ms) + _encode_random(_RANDOM_LEN)