80 lines
3.2 KiB
Python
80 lines
3.2 KiB
Python
import os
|
|
from django.conf import settings
|
|
from django.core.management.base import BaseCommand
|
|
from boxes.models import ThingFile
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Clean up orphaned files from deleted things'
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
'--dry-run',
|
|
action='store_true',
|
|
dest='dry_run',
|
|
help='Show what would be deleted without actually deleting',
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
dry_run = options.get('dry_run', False)
|
|
|
|
if dry_run:
|
|
self.stdout.write(self.style.WARNING('DRY RUN - No files will be deleted'))
|
|
|
|
self.stdout.write('Finding orphaned files...')
|
|
|
|
media_root = settings.MEDIA_ROOT
|
|
things_files_root = os.path.join(media_root, 'things', 'files')
|
|
|
|
if not os.path.exists(things_files_root):
|
|
self.stdout.write(self.style.WARNING('No things/files directory found'))
|
|
return
|
|
|
|
valid_paths = set()
|
|
for thing_file in ThingFile.objects.all():
|
|
if thing_file.file:
|
|
file_path = thing_file.file.path
|
|
if os.path.exists(file_path):
|
|
valid_paths.add(os.path.relpath(file_path, things_files_root))
|
|
|
|
self.stdout.write(f'Found {len(valid_paths)} valid files in database')
|
|
|
|
deleted_count = 0
|
|
empty_dirs_removed = 0
|
|
|
|
for root, dirs, files in os.walk(things_files_root, topdown=False):
|
|
for filename in files:
|
|
file_path = os.path.join(root, filename)
|
|
relative_path = os.path.relpath(file_path, things_files_root)
|
|
|
|
if relative_path not in valid_paths:
|
|
deleted_count += 1
|
|
if dry_run:
|
|
self.stdout.write(f'Would delete: {file_path}')
|
|
else:
|
|
try:
|
|
os.remove(file_path)
|
|
self.stdout.write(f'Deleted: {file_path}')
|
|
except OSError as e:
|
|
self.stdout.write(self.style.ERROR(f'Failed to delete {file_path}: {e}'))
|
|
|
|
for dirname in dirs:
|
|
dir_path = os.path.join(root, dirname)
|
|
if not os.listdir(dir_path):
|
|
if dry_run:
|
|
self.stdout.write(f'Would remove empty directory: {dir_path}')
|
|
else:
|
|
try:
|
|
os.rmdir(dir_path)
|
|
self.stdout.write(f'Removed empty directory: {dir_path}')
|
|
empty_dirs_removed += 1
|
|
except OSError as e:
|
|
self.stdout.write(self.style.ERROR(f'Failed to remove {dir_path}: {e}'))
|
|
|
|
if dry_run:
|
|
self.stdout.write(self.style.WARNING(f'\nDry run complete. Would delete {deleted_count} files'))
|
|
self.stdout.write(f'Would remove {empty_dirs_removed} empty directories')
|
|
else:
|
|
self.stdout.write(self.style.SUCCESS(f'\nCleanup complete! Deleted {deleted_count} orphaned files'))
|
|
self.stdout.write(f'Removed {empty_dirs_removed} empty directories')
|