Fixed #26297 -- Fixed `collectstatic --clear` crash if storage doesn't implement path().

This commit is contained in:
Berker Peksag 2016-03-14 05:17:05 +02:00 committed by Tim Graham
parent ecb59cc657
commit 28bcff82c5
4 changed files with 54 additions and 5 deletions

View File

@ -221,12 +221,16 @@ class Command(BaseCommand):
smart_text(fpath), level=1) smart_text(fpath), level=1)
else: else:
self.log("Deleting '%s'" % smart_text(fpath), level=1) self.log("Deleting '%s'" % smart_text(fpath), level=1)
full_path = self.storage.path(fpath) try:
if not os.path.exists(full_path) and os.path.lexists(full_path): full_path = self.storage.path(fpath)
# Delete broken symlinks except NotImplementedError:
os.unlink(full_path)
else:
self.storage.delete(fpath) self.storage.delete(fpath)
else:
if not os.path.exists(full_path) and os.path.lexists(full_path):
# Delete broken symlinks
os.unlink(full_path)
else:
self.storage.delete(fpath)
for d in dirs: for d in dirs:
self.clear_dir(os.path.join(path, d)) self.clear_dir(os.path.join(path, d))

View File

@ -27,3 +27,6 @@ Bugfixes
earlier versions of Django. earlier versions of Django.
* Fixed a memory leak in the cached template loader (:ticket:`26306`). * Fixed a memory leak in the cached template loader (:ticket:`26306`).
* Fixed a regression that caused ``collectstatic --clear`` to fail if the
storage doesn't implement ``path()`` (:ticket:`26297`).

View File

@ -1,5 +1,8 @@
import errno
import os
from datetime import datetime from datetime import datetime
from django.conf import settings
from django.contrib.staticfiles.storage import CachedStaticFilesStorage from django.contrib.staticfiles.storage import CachedStaticFilesStorage
from django.core.files import storage from django.core.files import storage
from django.utils import timezone from django.utils import timezone
@ -22,6 +25,40 @@ class DummyStorage(storage.Storage):
return datetime.datetime(1970, 1, 1, tzinfo=timezone.utc) return datetime.datetime(1970, 1, 1, tzinfo=timezone.utc)
class PathNotImplementedStorage(storage.Storage):
def _save(self, name, content):
return 'dummy'
def _path(self, name):
return os.path.join(settings.STATIC_ROOT, name)
def exists(self, name):
return os.path.exists(self._path(name))
def listdir(self, path):
path = self._path(path)
directories, files = [], []
for entry in os.listdir(path):
if os.path.isdir(os.path.join(path, entry)):
directories.append(entry)
else:
files.append(entry)
return directories, files
def delete(self, name):
name = self._path(name)
if os.path.exists(name):
try:
os.remove(name)
except OSError as e:
if e.errno != errno.ENOENT:
raise
def path(self, name):
raise NotImplementedError
class SimpleCachedStaticFilesStorage(CachedStaticFilesStorage): class SimpleCachedStaticFilesStorage(CachedStaticFilesStorage):
def file_hash(self, name, content=None): def file_hash(self, name, content=None):

View File

@ -170,6 +170,11 @@ class TestCollectionClear(CollectionTestCase):
shutil.rmtree(six.text_type(settings.STATIC_ROOT)) shutil.rmtree(six.text_type(settings.STATIC_ROOT))
super(TestCollectionClear, self).run_collectstatic(clear=True) super(TestCollectionClear, self).run_collectstatic(clear=True)
@override_settings(STATICFILES_STORAGE='staticfiles_tests.storage.PathNotImplementedStorage')
def test_handle_path_notimplemented(self):
self.run_collectstatic()
self.assertFileNotFound('cleared.txt')
class TestCollectionExcludeNoDefaultIgnore(CollectionTestCase, TestDefaults): class TestCollectionExcludeNoDefaultIgnore(CollectionTestCase, TestDefaults):
""" """