archive_logs.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import shutil
  2. import xml.etree.ElementTree as ET
  3. from datetime import datetime, timedelta
  4. from pathlib import Path
  5. def find_xml_files(directory: Path) -> list[Path]:
  6. archive_directory = directory / "Archiv"
  7. return sorted(
  8. path
  9. for path in directory.rglob("*")
  10. if path.is_file()
  11. and path.suffix.lower() == ".xml"
  12. and not path.name.lower().startswith("sessions")
  13. and archive_directory not in path.parents
  14. )
  15. def get_archive_year(xml_path: Path, now: datetime | None = None) -> int | None:
  16. try:
  17. root = ET.parse(xml_path).getroot()
  18. except ET.ParseError:
  19. return None
  20. session = root.find("Session")
  21. if session is None:
  22. return None
  23. if session.get("Duration", "").strip():
  24. start_time = session.get("StartTime", "")
  25. try:
  26. return datetime.fromisoformat(start_time.replace("Z", "+00:00")).year
  27. except ValueError:
  28. return None
  29. created_at = datetime.fromtimestamp(xml_path.stat().st_birthtime)
  30. now = now or datetime.now()
  31. if now - created_at >= timedelta(days=30):
  32. return created_at.year
  33. return None
  34. def remove_empty_directories(directory: Path) -> int:
  35. archive_directory = directory / "Archiv"
  36. removed_count = 0
  37. subdirectories = sorted(
  38. (path for path in directory.rglob("*") if path.is_dir()),
  39. key=lambda path: len(path.parts),
  40. reverse=True,
  41. )
  42. for subdirectory in subdirectories:
  43. if subdirectory == archive_directory or archive_directory in subdirectory.parents:
  44. continue
  45. try:
  46. subdirectory.rmdir()
  47. except OSError:
  48. continue
  49. removed_count += 1
  50. return removed_count
  51. def run(directory: Path) -> tuple[int, int, int]:
  52. if not directory.is_dir():
  53. raise ValueError(f"Das Verzeichnis existiert nicht: {directory}")
  54. checked_count = 0
  55. archived_count = 0
  56. skipped_count = 0
  57. for xml_file in find_xml_files(directory):
  58. checked_count += 1
  59. year = get_archive_year(xml_file)
  60. if year is None:
  61. skipped_count += 1
  62. continue
  63. target_directory = directory / "Archiv" / str(year)
  64. target_directory.mkdir(parents=True, exist_ok=True)
  65. target = target_directory / xml_file.name
  66. if target.exists():
  67. skipped_count += 1
  68. continue
  69. shutil.move(str(xml_file), str(target))
  70. archived_count += 1
  71. remove_empty_directories(directory)
  72. return checked_count, archived_count, skipped_count