Browse Source

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.
Loic Bistuer 11 years ago
parent
commit
4befb3015c

+ 1 - 1
django/conf/global_settings.py

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

+ 23 - 17
django/contrib/staticfiles/management/commands/collectstatic.py

@@ -137,32 +137,38 @@ class Command(NoArgsCommand):
 
     def handle_noargs(self, **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):
             destination_path = self.storage.location
-            destination_display = ':\n\n    %s' % destination_path
+            message.append(':\n\n    %s\n\n' % destination_path)
         else:
             destination_path = None
-            destination_display = '.'
+            message.append('.\n\n')
 
         if self.clear:
-            clear_display = 'This will DELETE EXISTING FILES!'
+            message.append('This will DELETE EXISTING FILES!\n')
         else:
-            clear_display = 'This will overwrite existing files!'
-
-        if self.interactive:
-            confirm = input("""
-You have requested to collect static files at the destination
-location as specified in your settings%s
+            message.append('This will overwrite existing files!\n')
 
-%s
-Are you sure you want to do this?
+        message.append(
+            'Are you sure you want to do this?\n\n'
+            "Type 'yes' to continue, or 'no' to cancel: "
+        )
 
-Type 'yes' to continue, or 'no' to cancel: """
-% (destination_display, clear_display))
-            if confirm != 'yes':
-                raise CommandError("Collecting static files cancelled.")
+        if self.interactive and input(''.join(message)) != 'yes':
+            raise CommandError("Collecting static files cancelled.")
 
         collected = self.collect()
         modified_count = len(collected['modified'])

+ 4 - 7
django/contrib/staticfiles/storage.py

@@ -32,16 +32,13 @@ class StaticFilesStorage(FileSystemStorage):
             location = settings.STATIC_ROOT
         if base_url is None:
             base_url = settings.STATIC_URL
-        check_settings(base_url)
-        super(StaticFilesStorage, self).__init__(location, base_url,
-                                                 *args, **kwargs)
-
-    def path(self, name):
-        if not self.location:
+        if not location:
             raise ImproperlyConfigured("You're using the staticfiles app "
                                        "without having set the STATIC_ROOT "
                                        "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):

+ 1 - 1
docs/ref/settings.txt

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

+ 5 - 0
docs/releases/1.6.2.txt

@@ -14,3 +14,8 @@ Bug fixes
 
 * Fixed a crash when executing the :djadmin:`changepassword` command when the
   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.

+ 11 - 0
tests/staticfiles_tests/tests.py

@@ -224,6 +224,17 @@ class TestFindStatic(CollectionTestCase, TestDefaults):
         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):
     """
     Test ``collectstatic`` management command.