Commit 6a9ed7d4 authored by Vajrasky Kok's avatar Vajrasky Kok Committed by Jannis Leidel
Browse files

Fixed #19879 -- Have 'findstatic' says on which directories it searched the relative paths.

Added searched_locations in finders module. Added verbosity flag level 2 on 'findstatic'
command that will output the directories on which it searched the relative paths.

Reported by ccurvey. Initial patch by Jonas Svensson and Vajrasky Kok.
parent 935e6c1d
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -12,11 +12,15 @@ from django.utils import six, lru_cache

from django.contrib.staticfiles import utils

# To keep track on which directories the finder has searched the static files.
searched_locations = []


class BaseFinder(object):
    """
    A base file finder to be used for custom staticfiles finder classes.
    """

    def find(self, path, all=False):
        """
        Given a relative file path this ought to find an
@@ -75,6 +79,8 @@ class FileSystemFinder(BaseFinder):
        """
        matches = []
        for prefix, root in self.locations:
            if root not in searched_locations:
                searched_locations.append(root)
            matched_path = self.find_location(root, path, prefix)
            if matched_path:
                if not all:
@@ -147,6 +153,9 @@ class AppDirectoriesFinder(BaseFinder):
        """
        matches = []
        for app in self.apps:
            app_location = self.storages[app].location
            if app_location not in searched_locations:
                searched_locations.append(app_location)
            match = self.find_in_app(app, path)
            if match:
                if not all:
@@ -195,6 +204,8 @@ class BaseStorageFinder(BaseFinder):
        except NotImplementedError:
            pass
        else:
            if self.storage.location not in searched_locations:
                searched_locations.append(self.storage.location)
            if self.storage.exists(path):
                match = self.storage.path(path)
                if all:
@@ -232,6 +243,7 @@ def find(path, all=False):
    If ``all`` is ``False`` (default), return the first matching
    absolute path (or ``None`` if no match). Otherwise return a list.
    """
    searched_locations[:] = []
    matches = []
    for finder in get_finders():
        result = finder.find(path, all=all)
+13 −3
Original line number Diff line number Diff line
@@ -21,15 +21,25 @@ class Command(LabelCommand):
        verbosity = int(options.get('verbosity', 1))
        result = finders.find(path, all=options['all'])
        path = force_text(path)
        if verbosity >= 2:
            searched_locations = ("Looking in the following locations:\n  %s" %
                                  "\n  ".join(force_text(location)
                                  for location in finders.searched_locations))
        else:
            searched_locations = ''
        if result:
            if not isinstance(result, (list, tuple)):
                result = [result]
            result = (force_text(os.path.realpath(path)) for path in result)
            if verbosity >= 1:
                output = '\n  '.join(result)
                return "Found '%s' here:\n  %s" % (path, output)
                file_list = '\n  '.join(result)
                return ("Found '%s' here:\n  %s\n%s" %
                        (path, file_list, searched_locations))
            else:
                return '\n'.join(result)
        else:
            message = ["No matching file found for '%s'." % path]
            if verbosity >= 2:
                message.append(searched_locations)
            if verbosity >= 1:
                self.stderr.write("No matching file found for '%s'." % path)
                self.stderr.write('\n'.join(message))
+34 −0
Original line number Diff line number Diff line
@@ -162,6 +162,23 @@ output and just get the path names::
   /home/special.polls.com/core/static/css/base.css
   /home/polls.com/core/static/css/base.css

On the other hand, by setting the :djadminopt:`--verbosity` flag to 2, you can
get all the directories on which it searched the relative paths::

   $ python manage.py findstatic css/base.css --verbosity 2
   Found 'css/base.css' here:
     /home/special.polls.com/core/static/css/base.css
     /home/polls.com/core/static/css/base.css
   Looking in the following locations:
     /home/special.polls.com/core/static
     /home/polls.com/core/static
     /some/other/path/static

.. versionadded:: 1.7

   The additional message of on which directories it searched the relative
   paths is new in Django 1.7.

.. _staticfiles-runserver:

runserver
@@ -366,6 +383,23 @@ files:

.. _staticfiles-development-view:

Finders Module
==============

``staticfiles`` finders has a ``searched_locations`` list with directory paths
in which they search for the relative paths. Example usage::

    from django.contrib.staticfiles import finders

    result = finders.find('css/base.css')
    searched_locations = finders.searched_locations

.. versionadded:: 1.7

The ``get_searched_locations`` function is new in Django 1.7. Previously, we
have to check the locations of our :setting:`STATICFILES_FINDERS` manually
one by one.

Static file development view
----------------------------

+4 −0
Original line number Diff line number Diff line
@@ -1051,6 +1051,10 @@ Miscellaneous
  which does allow primary keys with value 0. It only forbids *autoincrement*
  primary keys with value 0.

* :djadmin:`findstatic` now accepts verbosity flag level 2, meaning it will
  show the directories on which it searched the relative paths. See
  :djadmin:`findstatic` for example output.

.. _deprecated-features-1.7:

Features deprecated in 1.7
+37 −0
Original line number Diff line number Diff line
@@ -223,6 +223,35 @@ class TestFindStatic(CollectionTestCase, TestDefaults):
        self.assertIn('project', force_text(lines[0]))
        self.assertIn('apps', force_text(lines[1]))

    def test_all_files_more_verbose(self):
        """
        Test that findstatic returns all candidate files if run without --first and -v2.
        Also, test that findstatic returns the searched locations with -v2.
        """
        out = six.StringIO()
        call_command('findstatic', 'test/file.txt', verbosity=2, stdout=out)
        out.seek(0)
        lines = [l.strip() for l in out.readlines()]
        self.assertIn('project', force_text(lines[1]))
        self.assertIn('apps', force_text(lines[2]))
        self.assertIn("Looking in the following locations:", force_text(lines[3]))
        searched_locations = ', '.join(lines[4:])
        #AppDirectoriesFinder searched locations
        self.assertIn(os.path.join('staticfiles_tests', 'apps', 'test', 'static'),
                      searched_locations)
        self.assertIn(os.path.join('staticfiles_tests', 'apps', 'no_label', 'static'),
                      searched_locations)
        self.assertIn(os.path.join('django', 'contrib', 'admin', 'static'),
                      searched_locations)
        self.assertIn(os.path.join('django', 'tests', 'servers', 'another_app', 'static'),
                      searched_locations)
        #FileSystemFinder searched locations
        self.assertIn(TEST_SETTINGS['STATICFILES_DIRS'][1][1], searched_locations)
        self.assertIn(TEST_SETTINGS['STATICFILES_DIRS'][0], searched_locations)
        #DefaultStorageFinder searched locations
        self.assertIn(os.path.join('staticfiles_tests', 'project', 'site_media', 'media'),
                      searched_locations)


class TestConfiguration(StaticFilesTestCase):
    def test_location_empty(self):
@@ -779,6 +808,9 @@ class TestDefaultStorageFinder(StaticFilesTestCase, FinderTestCase):
        self.find_all = ('media-file.txt', [test_file_path])


@override_settings(STATICFILES_FINDERS=
                   ('django.contrib.staticfiles.finders.FileSystemFinder',),
                   STATICFILES_DIRS=[os.path.join(TEST_ROOT, 'project', 'documents')])
class TestMiscFinder(TestCase):
    """
    A few misc finder tests.
@@ -805,6 +837,11 @@ class TestMiscFinder(TestCase):
        self.assertEqual(cache_info.hits, 9)
        self.assertEqual(cache_info.currsize, 1)

    def test_searched_locations(self):
        finders.find('spam')
        self.assertEqual(finders.searched_locations,
                         [os.path.join(TEST_ROOT, 'project', 'documents')])

    @override_settings(STATICFILES_DIRS='a string')
    def test_non_tuple_raises_exception(self):
        """