screen-locker/scripts/add_scheduled_skip.py
2026-09-11 18:46:28 +02:00

83 lines
2.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""Mark a day free, for this app and every other gate app at once.
This used to append to ``screen_locker/scheduled_skips.json``, which only
screen-locker read. That file is no longer consulted by anything: the lock
chain now asks the shared pool (``~/src/utils/freedays``), so a day taken here
also stands down diet-guard, wake-alarm, leetcode-guard and home-guard.
Kept as a thin wrapper rather than deleted because ``arm.sh`` calls it, and
because this is the name already in muscle memory. ``freedays mark`` does
exactly the same thing.
scripts/add_scheduled_skip.py --date today
scripts/add_scheduled_skip.py --date 2026-12-24
The date is **local**. The old version computed a local "today" while the
lock chain compared against a UTC one, so a skip added near midnight could
name a date the chain never matched. freedays owns "what is today" for both
sides now, so that disagreement cannot recur.
"""
from __future__ import annotations
import argparse
import logging
import sys
import freedays
_logger = logging.getLogger(__name__)
def _report(message: str) -> None:
sys.stdout.write(f"{message}\n")
def main(argv: list[str] | None = None) -> int:
"""Mark the requested day free in the shared pool.
Returns:
``0`` when the day is free (including when it already was), ``1``
when the pool refused, ``2`` when the date could not be parsed.
"""
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
parser.add_argument(
"--date",
default="today",
help="YYYY-MM-DD, or 'today'/'tomorrow' (default: today)",
)
parser.add_argument(
"--reason",
default="",
help="optional free text; never required",
)
args = parser.parse_args(argv)
try:
day = freedays.resolve(args.date)
except ValueError as exc:
_logger.warning("could not parse the requested date: %s", exc)
_report(f"error: {exc}")
return 2
iso = freedays.to_iso(day)
if freedays.is_free_day(day):
_report(f"{iso} is already a free day; nothing to do")
return 0
try:
freedays.mark(day, reason=args.reason)
except freedays.FreeDayError as exc:
_logger.warning("the pool refused %s: %s", iso, exc)
_report(f"error: {exc}")
return 1
left = freedays.status(year=day.year).left
_report(f"{iso} is now a free day for every gate app ({left} left in {day.year})")
return 0
if __name__ == "__main__":
sys.exit(main())