bgneal@665: """dlorphan - a management command to remove orphaned downloads files.""" bgneal@665: bgneal@665: from optparse import make_option bgneal@665: import os bgneal@665: bgneal@665: from django.core.management.base import NoArgsCommand bgneal@665: from django.conf import settings bgneal@665: bgneal@665: from downloads.models import Download, PendingDownload bgneal@665: bgneal@665: bgneal@665: class Command(NoArgsCommand): bgneal@665: help = "Finds and optionally deletes orphan downloads files" bgneal@665: option_list = NoArgsCommand.option_list + ( bgneal@665: make_option('--delete', bgneal@665: action='store_true', bgneal@665: dest='delete', bgneal@665: default=False, bgneal@665: help='Delete orphan files'), bgneal@665: ) bgneal@665: bgneal@665: def handle_noargs(self, **options): bgneal@665: """Find and optionally delete orphan downloads files.""" bgneal@665: bgneal@665: delete = options.get('delete', False) bgneal@665: bgneal@665: orphans = set() bgneal@665: missing_pending = [] bgneal@665: missing_dls = [] bgneal@665: bgneal@665: dls_dir = os.path.join(settings.MEDIA_ROOT, 'downloads') bgneal@665: # find the set of all files in the downloads area bgneal@665: for root, dirs, files in os.walk(dls_dir, followlinks=True): bgneal@665: for name in files: bgneal@665: orphans.add(unicode(os.path.join(root, name), 'utf-8')) bgneal@665: bgneal@665: # examine the pending downloads: bgneal@665: for dl in PendingDownload.objects.iterator(): bgneal@665: try: bgneal@665: orphans.remove(dl.file.path) bgneal@665: except KeyError: bgneal@665: missing_pending.append(dl) bgneal@665: bgneal@665: # examine the downloads: bgneal@665: for dl in Download.objects.iterator(): bgneal@665: try: bgneal@665: orphans.remove(dl.file.path) bgneal@665: except KeyError: bgneal@665: missing_dls.append(dl) bgneal@665: bgneal@667: if orphans and delete: bgneal@667: for path in orphans: bgneal@667: self.stdout.write("Deleting: {}\n".format(path)) bgneal@667: os.remove(path) bgneal@667: elif orphans: bgneal@667: self.stdout.write("Orphan files:\n") bgneal@665: for orphan in orphans: bgneal@667: self.stdout.write("{}\n".format(orphan)) bgneal@665: bgneal@665: if missing_pending: bgneal@667: self.stdout.write("PendingDownloads with missing files:\n") bgneal@665: for dl in missing_pending: bgneal@667: self.stdout.write("{}\n".format(dl)) bgneal@665: bgneal@665: if missing_dls: bgneal@667: self.stdout.write("Downloads with missing files:\n") bgneal@665: for dl in missing_dls: bgneal@667: self.stdout.write("{}\n".format(dl)) bgneal@665: bgneal@667: empty_dirs = [] bgneal@667: # check for empty directories after deletions bgneal@667: for root, dirs, files in os.walk(dls_dir, followlinks=True): bgneal@667: if not len(dirs) and not len(files): bgneal@667: empty_dirs.append(root) bgneal@665: bgneal@667: if empty_dirs and delete: bgneal@665: for path in empty_dirs: bgneal@667: self.stdout.write("Deleting empty dir: {}\n".format(path)) bgneal@665: os.removedirs(path) bgneal@667: elif empty_dirs: bgneal@667: self.stdout.write("Empty directories:\n") bgneal@667: for d in empty_dirs: bgneal@667: self.stdout.write("{}\n".format(d))