Source code for htr2hpc.management.commands.cleanup_exports

import datetime
from pathlib import Path
from typing import Generator

from django.conf import settings
from django.core.management.base import BaseCommand


[docs] def get_old_exports( users_dir: Path, cutoff: datetime.datetime ) -> Generator[tuple[Path, int], None, None]: """Yield (path, size_in_bytes) for export files older than cutoff.""" for entry in users_dir.glob("*/export_*.zip"): try: stat = entry.stat() except OSError: continue mtime = datetime.datetime.fromtimestamp(stat.st_mtime) if mtime < cutoff: yield entry, stat.st_size
[docs] class Command(BaseCommand): help = ( "Delete export files (export_*.zip) under MEDIA_ROOT/users/ " "older than settings.EXPORT_FILE_RETENTION hours." ) v_normal = 1
[docs] def add_arguments(self, parser): parser.add_argument( "--dry-run", action="store_true", default=False, help="Report what would be deleted without actually deleting.", )
[docs] def delete_old_exports( self, export_dir: Path, retention_hours: int ) -> tuple[int, int]: """Delete export files in export_dir older than retention_hours. Returns a (count, total_bytes) tuple of files deleted (or that would be deleted when dry_run=True). """ cutoff = datetime.datetime.now() - datetime.timedelta(hours=retention_hours) if not export_dir.is_dir(): return 0, 0 count = 0 total_bytes = 0 for entry, size in get_old_exports(export_dir, cutoff): if self.dry_run or self.verbosity >= self.v_normal + 1: action = "Would delete" if self.dry_run else "Deleting" self.stdout.write(f"{action} {entry} ({size} bytes)") if not self.dry_run: try: entry.unlink() except OSError: continue count += 1 total_bytes += size return count, total_bytes
[docs] def handle(self, *args, **kwargs): self.dry_run = kwargs["dry_run"] self.verbosity = kwargs["verbosity"] retention = settings.EXPORT_FILE_RETENTION if retention == 0: self.stdout.write( "EXPORT_FILE_RETENTION set to 0. Nothing will be cleaned up." ) return export_dir = Path(settings.MEDIA_ROOT) / "users" if not export_dir.is_dir(): self.stdout.write("No users media directory found; nothing to clean up.") return count, total_bytes = self.delete_old_exports(export_dir, retention) if self.verbosity >= self.v_normal: action = "Would delete" if self.dry_run else "Deleted" self.stdout.write( f"{action} {count} export file(s), freeing {total_bytes} bytes." )