Fixed #21581 -- Fixed a number of issues with collectstatic.

When STATIC_ROOT wasn't set, collectstatic --clear would delete
every files within the current directory and its descendants.

This patch makes the following changes:

Prevent collectstatic from running if STATIC_ROOT isn't set.

Fixed an issue that prevented collectstatic from displaying the
destination directory.

Changed the warning header to notify when the command is run
in dry-run mode.
This commit is contained in:
Loic Bistuer 2013-12-10 00:29:39 +07:00 committed by Tim Graham
parent 4d8d76e7a8
commit 4befb3015c
6 changed files with 45 additions and 26 deletions

View File

@ -290,7 +290,7 @@ MEDIA_URL = ''
# Absolute path to the directory static files should be collected to. # Absolute path to the directory static files should be collected to.
# Example: "/var/www/example.com/static/" # Example: "/var/www/example.com/static/"
STATIC_ROOT = '' STATIC_ROOT = None
# URL that handles the static files served from STATIC_ROOT. # URL that handles the static files served from STATIC_ROOT.
# Example: "http://example.com/static/", "http://static.example.com/" # Example: "http://example.com/static/", "http://static.example.com/"

View File

@ -137,32 +137,38 @@ class Command(NoArgsCommand):
def handle_noargs(self, **options): def handle_noargs(self, **options):
self.set_options(**options) self.set_options(**options)
# Warn before doing anything more.
if (isinstance(self.storage, FileSystemStorage) and message = ['\n']
if self.dry_run:
message.append(
'You have activated the --dry-run option so no files will be modified.\n\n'
)
message.append(
'You have requested to collect static files at the destination\n'
'location as specified in your settings'
)
if (isinstance(self.storage._wrapped, FileSystemStorage) and
self.storage.location): self.storage.location):
destination_path = self.storage.location destination_path = self.storage.location
destination_display = ':\n\n %s' % destination_path message.append(':\n\n %s\n\n' % destination_path)
else: else:
destination_path = None destination_path = None
destination_display = '.' message.append('.\n\n')
if self.clear: if self.clear:
clear_display = 'This will DELETE EXISTING FILES!' message.append('This will DELETE EXISTING FILES!\n')
else: else:
clear_display = 'This will overwrite existing files!' message.append('This will overwrite existing files!\n')
if self.interactive: message.append(
confirm = input(""" 'Are you sure you want to do this?\n\n'
You have requested to collect static files at the destination "Type 'yes' to continue, or 'no' to cancel: "
location as specified in your settings%s )
%s if self.interactive and input(''.join(message)) != 'yes':
Are you sure you want to do this? raise CommandError("Collecting static files cancelled.")
Type 'yes' to continue, or 'no' to cancel: """
% (destination_display, clear_display))
if confirm != 'yes':
raise CommandError("Collecting static files cancelled.")
collected = self.collect() collected = self.collect()
modified_count = len(collected['modified']) modified_count = len(collected['modified'])

View File

@ -32,16 +32,13 @@ class StaticFilesStorage(FileSystemStorage):
location = settings.STATIC_ROOT location = settings.STATIC_ROOT
if base_url is None: if base_url is None:
base_url = settings.STATIC_URL base_url = settings.STATIC_URL
check_settings(base_url) if not location:
super(StaticFilesStorage, self).__init__(location, base_url,
*args, **kwargs)
def path(self, name):
if not self.location:
raise ImproperlyConfigured("You're using the staticfiles app " raise ImproperlyConfigured("You're using the staticfiles app "
"without having set the STATIC_ROOT " "without having set the STATIC_ROOT "
"setting to a filesystem path.") "setting to a filesystem path.")
return super(StaticFilesStorage, self).path(name) check_settings(base_url)
super(StaticFilesStorage, self).__init__(location, base_url,
*args, **kwargs)
class CachedFilesMixin(object): class CachedFilesMixin(object):

View File

@ -2535,7 +2535,7 @@ Settings for :mod:`django.contrib.staticfiles`.
STATIC_ROOT STATIC_ROOT
----------- -----------
Default: ``''`` (Empty string) Default: ``None``
The absolute path to the directory where :djadmin:`collectstatic` will collect The absolute path to the directory where :djadmin:`collectstatic` will collect
static files for deployment. static files for deployment.

View File

@ -14,3 +14,8 @@ Bug fixes
* Fixed a crash when executing the :djadmin:`changepassword` command when the * Fixed a crash when executing the :djadmin:`changepassword` command when the
user object representation contained non-ASCII characters (#21627). user object representation contained non-ASCII characters (#21627).
* The :djadmin:`collectstatic` command will raise an error rather than
default to using the current working directory if :setting:`STATIC_ROOT` is
not set. Combined with the ``--clear`` option, the previous behavior could
wipe anything below the current working directory.

View File

@ -224,6 +224,17 @@ class TestFindStatic(CollectionTestCase, TestDefaults):
self.assertIn('apps', force_text(lines[1])) self.assertIn('apps', force_text(lines[1]))
class TestConfiguration(StaticFilesTestCase):
def test_location_empty(self):
err = six.StringIO()
for root in ['', None]:
with override_settings(STATIC_ROOT=root):
with six.assertRaisesRegex(
self, ImproperlyConfigured,
'without having set the STATIC_ROOT setting to a filesystem path'):
call_command('collectstatic', interactive=False, verbosity=0, stderr=err)
class TestCollection(CollectionTestCase, TestDefaults): class TestCollection(CollectionTestCase, TestDefaults):
""" """
Test ``collectstatic`` management command. Test ``collectstatic`` management command.