mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-11 20:33:56 +01:00
Silent-failure checker, mypy, pylint now clean. Hidden packages count as installed (pm list -u), pull gets a long timeout, wifi entries are matched by ro.serialno, and a missing log/drop dir is a warning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzxdWZ9CKZsNxtD5Jr9bYD
100 lines
3.6 KiB
Python
100 lines
3.6 KiB
Python
"""``python3 -m screen_locker.runnerup_retire``: uninstall RunnerUp, a week on.
|
|
|
|
What ``runnerup-retire.service`` runs. ``--status`` prints anchor, due date,
|
|
marker validity and (with ``--query-phone``) whether RunnerUp is installed;
|
|
it never writes and never talks to the phone unless asked. ``--dry-run`` runs
|
|
every check, including the read-only adb queries, but writes nothing, pulls
|
|
nothing and uninstalls nothing. The exit code is non-zero only for outcomes
|
|
that need a human (bad marker, adb missing, failed backup or uninstall).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
from datetime import UTC, datetime
|
|
import logging
|
|
import sys
|
|
from typing import TYPE_CHECKING
|
|
|
|
from screen_locker._runnerup_retire import (
|
|
GRACE,
|
|
Paths,
|
|
derive_anchor,
|
|
run_retire,
|
|
)
|
|
from screen_locker._runnerup_retire_adb import PHONE_SERIAL, AdbError, Phone
|
|
from screen_locker._runnerup_retire_state import load_state
|
|
from screen_locker._runnerup_retire_tcx import check_marker
|
|
|
|
if TYPE_CHECKING:
|
|
from screen_locker._runnerup_retire_adb import PhoneLike
|
|
|
|
__all__ = ["main", "status_lines"]
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _installed_line(phone: PhoneLike, *, query: bool) -> str:
|
|
if not query:
|
|
return "installed: not queried (add --query-phone)"
|
|
try:
|
|
device = phone.find_device()
|
|
if device.serial is None:
|
|
return f"installed: unknown ({device.reason})"
|
|
return f"installed: {'yes' if phone.installed(device.serial) else 'no'}"
|
|
except AdbError as exc:
|
|
_logger.warning("--status could not ask the phone: %s", exc)
|
|
return f"installed: unknown ({exc})"
|
|
|
|
|
|
def status_lines(
|
|
paths: Paths, phone: PhoneLike, now: datetime, *, query_phone: bool = False
|
|
) -> list[str]:
|
|
"""The ``--status`` report. Read-only: nothing is created or saved."""
|
|
state = load_state(paths.state_file)
|
|
anchor = derive_anchor(paths, state)
|
|
if anchor is None:
|
|
anchor_line, due_line = "anchor: none (no app run credited yet)", "due: never"
|
|
else:
|
|
origin = "stored" if state.anchor_at else "derived, not yet stored"
|
|
due = anchor + GRACE
|
|
days = (due - now).total_seconds() / 86400
|
|
anchor_line = f"anchor: {anchor.isoformat()} ({origin})"
|
|
due_line = f"due: {due:%Y-%m-%d %H:%M} ({days:+.1f} days)"
|
|
marker = check_marker(paths.marker, paths.processed)
|
|
return [
|
|
anchor_line,
|
|
due_line,
|
|
f"marker: {'valid' if marker.ok else 'INVALID'} ({marker.reason})",
|
|
f"done: {state.done_at or 'no'}",
|
|
_installed_line(phone, query=query_phone),
|
|
]
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
"""CLI entry; returns the process exit code."""
|
|
parser = argparse.ArgumentParser(description=__doc__.split("\n\n", maxsplit=1)[0])
|
|
parser.add_argument(
|
|
"--status", action="store_true", help="print state, change nothing"
|
|
)
|
|
parser.add_argument(
|
|
"--dry-run", action="store_true", help="check everything, change nothing"
|
|
)
|
|
parser.add_argument(
|
|
"--query-phone", action="store_true", help="with --status: ask adb"
|
|
)
|
|
parser.add_argument("--serial", default=PHONE_SERIAL, help="phone adb serial")
|
|
args = parser.parse_args(argv)
|
|
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s")
|
|
paths, phone = Paths.default(), Phone(args.serial)
|
|
if args.status:
|
|
now = datetime.now(UTC)
|
|
lines = status_lines(paths, phone, now, query_phone=args.query_phone)
|
|
sys.stdout.write("\n".join(lines) + "\n")
|
|
return 0
|
|
return 0 if run_retire(paths, phone, dry_run=args.dry_run).ok else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|