GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — devstack/support/browser-state-cleanup.py at dev · lpb-stack/devstack Expand file tree/ Copy pathbrowser-state-cleanup.pyMore file actions 147 lines (121 loc) · 4.84 KB / Copy pathbrowser-state-cleanup.pyFile metadata and controls147 lines (121 loc) · 4.84 KB 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 #!/usr/bin/env python3 """browser-state-cleanup — housekeeping for agent-browser session state. Python port of support/browser-state-cleanup. Removes session dirs older than ``--max-age-days`` OR when the count exceeds ``--max-count``, keeping the most recent ones. Optionally kills orphaned Chrome/agent-browser processes first. State directory: ~/.agent-browser/sessions/ (survives container rebuilds; only old sessions are pruned). """ from __future__ import annotations import argparse import os import shutil import sys from datetime import datetime, timedelta from pathlib import Path _SELF_DIR = Path(__file__).resolve().parent for _candidate in (_SELF_DIR.parent / "scripts", _SELF_DIR): if (_candidate / "localpibox").is_dir(): sys.path.insert(0, str(_candidate)) break from localpibox.cli import add_common_args, console_from_args, install_sigpipe_handler # noqa: E402 from localpibox.log import Console # noqa: E402 from localpibox.run import run_cmd # noqa: E402 def session_dirs(state_dir: str | Path) -> list[Path]: """Directories directly under *state_dir*, oldest-first-irrelevant order.""" try: return sorted([p for p in Path(state_dir).iterdir() if p.is_dir()]) except OSError: return [] def prune_by_age( dirs: list[Path], max_age_days: int, now: datetime | None = None, ) -> tuple[list[Path], list[Path]]: """Split *dirs* into ``(removed, remaining)`` by mtime age. Directories whose mtime is older than ``max_age_days`` are removed. Directories whose mtime cannot be stat'd are kept. """ now = now or datetime.now() cutoff = now - timedelta(days=max_age_days) removed: list[Path] = [] remaining: list[Path] = [] for d in dirs: try: mtime = datetime.fromtimestamp(d.stat().st_mtime) except OSError: remaining.append(d) continue (removed if mtime < cutoff else remaining).append(d) return removed, remaining def prune_by_count( dirs: list[Path], max_count: int, ) -> tuple[list[Path], list[Path]]: """Trim *dirs* to at most ``max_count``, removing the oldest first.""" if len(dirs) <= max_count: return [], list(dirs) by_age = sorted(dirs, key=lambda p: p.stat().st_mtime) keep = by_age[-max_count:] return [d for d in by_age if d not in keep], keep def cleanup( state_dir: str | Path, *, max_age_days: int = 7, max_count: int = 20, remove: bool = True, now: datetime | None = None, ) -> tuple[list[Path], list[Path]]: """Prune *state_dir*; returns ``(removed, remaining)``. Age-based pruning runs first, then count-based pruning on the survivors. When ``remove=False`` (dry run) nothing is deleted and the returns still describe what *would* be removed/kept. """ dirs = session_dirs(state_dir) removed_by_age, dirs = prune_by_age(dirs, max_age_days, now=now) removed_by_count, dirs = prune_by_count(dirs, max_count) removed = removed_by_age + removed_by_count if remove: for d in removed: shutil.rmtree(d, ignore_errors=True) remaining = [d for d in dirs if d.exists()] else: remaining = list(dirs) return removed, remaining def kill_orphaned(cons: Console) -> None: """Best-effort kill of orphaned agent-browser / headless Chrome processes.""" for pattern in ("agent-browser", "chrome.*--headless"): _out, _err, _code = run_cmd(["pkill", "-f", pattern], timeout=10) cons.debug("orphaned browser processes cleaned") def main(argv: list[str] | None = None) -> int: install_sigpipe_handler() parser = argparse.ArgumentParser(prog="browser-state-cleanup", description=__doc__) add_common_args(parser) parser.add_argument( "--state-dir", default=str(Path.home() / ".agent-browser" / "sessions"), help="session state directory", ) parser.add_argument("--max-age-days", type=int, default=7, help="prune dirs older than N days") parser.add_argument("--max-count", type=int, default=20, help="keep at most N dirs") parser.add_argument("--no-kill", action="store_true", help="skip pkill of orphaned browsers") parser.add_argument("--dry-run", action="store_true", help="report only; delete nothing") args = parser.parse_args(argv) cons = console_from_args(args) state_dir = Path(args.state_dir) state_dir.mkdir(parents=True, exist_ok=True) if not args.no_kill: kill_orphaned(cons) removed, remaining = cleanup( state_dir, max_age_days=args.max_age_days, max_count=args.max_count, remove=not args.dry_run, ) for d in removed: cons.info(f" removed {d.name}" if not args.dry_run else f" would remove {d.name}") cons.info(f"Cleanup complete. Remaining sessions: {len(remaining)}") return 0 if __name__ == "__main__": raise SystemExit(main()) |
| You are visitor 01402520 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |