migrace /remind na sqlite
This commit is contained in:
124
scripts/migrate_yaml_to_sqlite.py
Normal file
124
scripts/migrate_yaml_to_sqlite.py
Normal file
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3
|
||||
# /// script
|
||||
# requires-python = ">=3.11"
|
||||
# dependencies = ["pyyaml"]
|
||||
# ///
|
||||
"""Migrate reminders from reminder.yaml to SQLite.
|
||||
|
||||
Reads reminder.yaml, inserts into reminders.sqlite, then renames YAML to .bak.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from os import environ
|
||||
from pathlib import Path
|
||||
|
||||
# db.py lives in skills/remind/scripts/
|
||||
SCRIPTS_DIR = Path(__file__).resolve().parent.parent / "skills" / "remind" / "scripts"
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
import yaml
|
||||
from db import get_db, init_db
|
||||
|
||||
WORKSPACE = Path(__file__).resolve().parent.parent
|
||||
YAML_PATH = WORKSPACE / "reminder.yaml"
|
||||
DEFAULT_DB_PATH = WORKSPACE / "db" / "reminders.sqlite"
|
||||
DB_PATH = Path(environ.get("REMIND_DB", str(DEFAULT_DB_PATH)))
|
||||
|
||||
|
||||
def _now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat(timespec="seconds")
|
||||
|
||||
|
||||
def _parse_window(window: str) -> tuple[int, int]:
|
||||
start_str, end_str = window.split("-", 1)
|
||||
start = _hhmm_to_minutes(start_str.strip())
|
||||
end = _hhmm_to_minutes(end_str.strip())
|
||||
return start, end
|
||||
|
||||
|
||||
def _hhmm_to_minutes(value: str) -> int:
|
||||
h, m = value.split(":")
|
||||
return int(h) * 60 + int(m)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not YAML_PATH.exists():
|
||||
print("No reminder.yaml found — nothing to migrate.")
|
||||
return 0
|
||||
|
||||
data = yaml.safe_load(YAML_PATH.read_text(encoding="utf-8")) or {}
|
||||
reminders = data.get("reminders", [])
|
||||
if not reminders:
|
||||
print("reminder.yaml is empty — nothing to migrate.")
|
||||
return 0
|
||||
|
||||
init_db(DB_PATH)
|
||||
conn = get_db(DB_PATH)
|
||||
try:
|
||||
conn.execute("BEGIN")
|
||||
for item in reminders:
|
||||
text = (item.get("text") or "").strip()
|
||||
if not text:
|
||||
continue
|
||||
now = _now()
|
||||
cur = conn.execute(
|
||||
"INSERT INTO reminders (text, enabled, timezone, created_at, updated_at) VALUES (?, 1, 'Europe/Prague', ?, ?)",
|
||||
(text, now, now),
|
||||
)
|
||||
rid = cur.lastrowid
|
||||
|
||||
at = item.get("at")
|
||||
at_times = item.get("at_times", [])
|
||||
if at:
|
||||
at_times = [at] + list(at_times)
|
||||
for at_str in at_times:
|
||||
conn.execute(
|
||||
"INSERT INTO schedule_at (reminder_id, at_datetime) VALUES (?, ?)",
|
||||
(rid, at_str),
|
||||
)
|
||||
|
||||
for expr in item.get("cron_exprs", []):
|
||||
conn.execute(
|
||||
"INSERT INTO schedule_cron (reminder_id, cron_expr) VALUES (?, ?)",
|
||||
(rid, expr),
|
||||
)
|
||||
|
||||
random_cfg = item.get("random")
|
||||
if random_cfg:
|
||||
start, end = _parse_window(random_cfg["window"])
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO schedule_random
|
||||
(reminder_id, times_per_day, window_start, window_end, days_filter, from_date, until_date)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
rid,
|
||||
random_cfg["times_per_day"],
|
||||
start,
|
||||
end,
|
||||
random_cfg.get("days"),
|
||||
random_cfg.get("from"),
|
||||
random_cfg.get("until"),
|
||||
),
|
||||
)
|
||||
|
||||
conn.execute("COMMIT")
|
||||
backup = YAML_PATH.with_suffix(".yaml.bak")
|
||||
YAML_PATH.rename(backup)
|
||||
print(f"Migrated {len(reminders)} reminders to {DB_PATH}")
|
||||
print(f"Renamed {YAML_PATH} to {backup}")
|
||||
return 0
|
||||
except Exception as exc:
|
||||
conn.execute("ROLLBACK")
|
||||
print(f"Migration failed: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user