Commit 64a0a33c authored by Jannis Leidel's avatar Jannis Leidel
Browse files

Fixed the staticfiles management commands collectstatic and findstatic to not...

Fixed the staticfiles management commands collectstatic and findstatic to not raise encoding related exceptions when handlings filenames with non-ASCII characters.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15538 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 6eacbfd4
Loading
Loading
Loading
Loading
+14 −12
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ from optparse import make_option
from django.conf import settings
from django.core.files.storage import get_storage_class
from django.core.management.base import CommandError, NoArgsCommand
from django.utils.encoding import smart_str

from django.contrib.staticfiles import finders

@@ -64,7 +65,7 @@ class Command(NoArgsCommand):

        # Warn before doing anything more.
        if options.get('interactive'):
            confirm = raw_input("""
            confirm = raw_input(u"""
You have requested to collect static files at the destination
location as specified in your settings file ('%s').

@@ -90,17 +91,18 @@ Type 'yes' to continue, or 'no' to cancel: """ % settings.STATIC_ROOT)
        actual_count = len(self.copied_files) + len(self.symlinked_files)
        unmodified_count = len(self.unmodified_files)
        if self.verbosity >= 1:
            self.stdout.write("\n%s static file%s %s to '%s'%s.\n"
            self.stdout.write(smart_str(u"\n%s static file%s %s to '%s'%s.\n"
                              % (actual_count, actual_count != 1 and 's' or '',
                                 symlink and 'symlinked' or 'copied',
                                 settings.STATIC_ROOT,
                                 unmodified_count and ' (%s unmodified)'
                                 % unmodified_count or ''))
                                 % unmodified_count or '')))

    def log(self, msg, level=2):
        """
        Small log helper
        """
        msg = smart_str(msg)
        if not msg.endswith("\n"):
            msg += "\n"
        if self.verbosity >= level:
@@ -135,13 +137,13 @@ Type 'yes' to continue, or 'no' to cancel: """ % settings.STATIC_ROOT)
                                (not symlink and full_path and os.path.islink(full_path))):
                            if prefixed_path not in self.unmodified_files:
                                self.unmodified_files.append(prefixed_path)
                            self.log("Skipping '%s' (not modified)" % path)
                            self.log(u"Skipping '%s' (not modified)" % path)
                            return False
            # Then delete the existing file if really needed
            if options['dry_run']:
                self.log("Pretending to delete '%s'" % path)
                self.log(u"Pretending to delete '%s'" % path)
            else:
                self.log("Deleting '%s'" % path)
                self.log(u"Deleting '%s'" % path)
                self.storage.delete(prefixed_path)
        return True

@@ -151,7 +153,7 @@ Type 'yes' to continue, or 'no' to cancel: """ % settings.STATIC_ROOT)
        """
        # Skip this file if it was already copied earlier
        if prefixed_path in self.symlinked_files:
            return self.log("Skipping '%s' (already linked earlier)" % path)
            return self.log(u"Skipping '%s' (already linked earlier)" % path)
        # Delete the target file if needed or break
        if not self.delete_file(path, prefixed_path, source_storage, **options):
            return
@@ -159,9 +161,9 @@ Type 'yes' to continue, or 'no' to cancel: """ % settings.STATIC_ROOT)
        source_path = source_storage.path(path)
        # Finally link the file
        if options['dry_run']:
            self.log("Pretending to link '%s'" % source_path, level=1)
            self.log(u"Pretending to link '%s'" % source_path, level=1)
        else:
            self.log("Linking '%s'" % source_path, level=1)
            self.log(u"Linking '%s'" % source_path, level=1)
            full_path = self.storage.path(prefixed_path)
            try:
                os.makedirs(os.path.dirname(full_path))
@@ -177,7 +179,7 @@ Type 'yes' to continue, or 'no' to cancel: """ % settings.STATIC_ROOT)
        """
        # Skip this file if it was already copied earlier
        if prefixed_path in self.copied_files:
            return self.log("Skipping '%s' (already copied earlier)" % path)
            return self.log(u"Skipping '%s' (already copied earlier)" % path)
        # Delete the target file if needed or break
        if not self.delete_file(path, prefixed_path, source_storage, **options):
            return
@@ -185,9 +187,9 @@ Type 'yes' to continue, or 'no' to cancel: """ % settings.STATIC_ROOT)
        source_path = source_storage.path(path)
        # Finally start copying
        if options['dry_run']:
            self.log("Pretending to copy '%s'" % source_path, level=1)
            self.log(u"Pretending to copy '%s'" % source_path, level=1)
        else:
            self.log("Copying '%s'" % source_path, level=1)
            self.log(u"Copying '%s'" % source_path, level=1)
            if self.local:
                full_path = self.storage.path(prefixed_path)
                try:
+8 −3
Original line number Diff line number Diff line
import os
from optparse import make_option
from django.core.management.base import LabelCommand
from django.utils.encoding import smart_str, smart_unicode

from django.contrib.staticfiles import finders

@@ -16,11 +17,15 @@ class Command(LabelCommand):
    def handle_label(self, path, **options):
        verbosity = int(options.get('verbosity', 1))
        result = finders.find(path, all=options['all'])
        path = smart_unicode(path)
        if result:
            if not isinstance(result, (list, tuple)):
                result = [result]
            output = '\n  '.join((os.path.realpath(path) for path in result))
            self.stdout.write("Found %r here:\n  %s\n" % (path, output))
            output = u'\n  '.join(
                (smart_unicode(os.path.realpath(path)) for path in result))
            self.stdout.write(
                smart_str(u"Found '%s' here:\n  %s\n" % (path, output)))
        else:
            if verbosity >= 1:
                self.stdout.write("No matching file found for %r.\n" % path)
                self.stderr.write(
                    smart_str("No matching file found for '%s'.\n" % path))
+2 −0
Original line number Diff line number Diff line
speçial in the app dir
 No newline at end of file
+14 −5
Original line number Diff line number Diff line
# -*- encoding: utf-8 -*-
import codecs
import os
import posixpath
import shutil
@@ -11,6 +13,7 @@ from django.core.exceptions import ImproperlyConfigured
from django.core.files.storage import default_storage
from django.core.management import call_command
from django.test import TestCase
from django.utils.encoding import smart_unicode
from django.utils._os import rmtree_errorhandler


@@ -72,8 +75,8 @@ class StaticFilesTestCase(TestCase):
        settings.INSTALLED_APPS = self.old_installed_apps

    def assertFileContains(self, filepath, text):
        self.assertTrue(text in self._get_file(filepath),
                        "'%s' not in '%s'" % (text, filepath))
        self.assertTrue(text in self._get_file(smart_unicode(filepath)),
                        u"'%s' not in '%s'" % (text, filepath))

    def assertFileNotFound(self, filepath):
        self.assertRaises(IOError, self._get_file, filepath)
@@ -108,7 +111,7 @@ class BuildStaticTestCase(StaticFilesTestCase):
    def _get_file(self, filepath):
        assert filepath, 'filepath is empty.'
        filepath = os.path.join(settings.STATIC_ROOT, filepath)
        f = open(filepath)
        f = codecs.open(filepath, "r", "utf-8")
        try:
            return f.read()
        finally:
@@ -140,10 +143,16 @@ class TestDefaults(object):

    def test_app_files(self):
        """
        Can find a file in an app media/ directory.
        Can find a file in an app static/ directory.
        """
        self.assertFileContains('test/file1.txt', 'file1 in the app dir')

    def test_nonascii_filenames(self):
        """
        Can find a file with non-ASCII character in an app static/ directory.
        """
        self.assertFileContains(u'test/speçial.txt', u'speçial in the app dir')


class TestFindStatic(BuildStaticTestCase, TestDefaults):
    """
@@ -156,7 +165,7 @@ class TestFindStatic(BuildStaticTestCase, TestDefaults):
            call_command('findstatic', filepath, all=False, verbosity='0')
            sys.stdout.seek(0)
            lines = [l.strip() for l in sys.stdout.readlines()]
            contents = open(lines[1].strip()).read()
            contents = codecs.open(lines[1].strip(), "r", "utf-8").read()
        finally:
            sys.stdout = _stdout
        return contents