Fixed #27590 -- Allowed customizing a manifest file storage in ManifestFilesMixin.
This commit is contained in:
parent
4fe3774c72
commit
d3c4696596
1
AUTHORS
1
AUTHORS
|
@ -423,6 +423,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Jan Rademaker
|
Jan Rademaker
|
||||||
Jarek Głowacki <jarekwg@gmail.com>
|
Jarek Głowacki <jarekwg@gmail.com>
|
||||||
Jarek Zgoda <jarek.zgoda@gmail.com>
|
Jarek Zgoda <jarek.zgoda@gmail.com>
|
||||||
|
Jarosław Wygoda <jaroslaw@wygoda.me>
|
||||||
Jason Davies (Esaj) <https://www.jasondavies.com/>
|
Jason Davies (Esaj) <https://www.jasondavies.com/>
|
||||||
Jason Huggins <http://www.jrandolph.com/blog/>
|
Jason Huggins <http://www.jrandolph.com/blog/>
|
||||||
Jason McBrayer <http://www.carcosa.net/jason/>
|
Jason McBrayer <http://www.carcosa.net/jason/>
|
||||||
|
|
|
@ -401,13 +401,16 @@ class ManifestFilesMixin(HashedFilesMixin):
|
||||||
manifest_strict = True
|
manifest_strict = True
|
||||||
keep_intermediate_files = False
|
keep_intermediate_files = False
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, manifest_storage=None, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
if manifest_storage is None:
|
||||||
|
manifest_storage = self
|
||||||
|
self.manifest_storage = manifest_storage
|
||||||
self.hashed_files = self.load_manifest()
|
self.hashed_files = self.load_manifest()
|
||||||
|
|
||||||
def read_manifest(self):
|
def read_manifest(self):
|
||||||
try:
|
try:
|
||||||
with self.open(self.manifest_name) as manifest:
|
with self.manifest_storage.open(self.manifest_name) as manifest:
|
||||||
return manifest.read().decode()
|
return manifest.read().decode()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return None
|
return None
|
||||||
|
@ -435,10 +438,10 @@ class ManifestFilesMixin(HashedFilesMixin):
|
||||||
|
|
||||||
def save_manifest(self):
|
def save_manifest(self):
|
||||||
payload = {'paths': self.hashed_files, 'version': self.manifest_version}
|
payload = {'paths': self.hashed_files, 'version': self.manifest_version}
|
||||||
if self.exists(self.manifest_name):
|
if self.manifest_storage.exists(self.manifest_name):
|
||||||
self.delete(self.manifest_name)
|
self.manifest_storage.delete(self.manifest_name)
|
||||||
contents = json.dumps(payload).encode()
|
contents = json.dumps(payload).encode()
|
||||||
self._save(self.manifest_name, ContentFile(contents))
|
self.manifest_storage._save(self.manifest_name, ContentFile(contents))
|
||||||
|
|
||||||
def stored_name(self, name):
|
def stored_name(self, name):
|
||||||
parsed_name = urlsplit(unquote(name))
|
parsed_name = urlsplit(unquote(name))
|
||||||
|
|
|
@ -313,6 +313,20 @@ For example, the ``'css/styles.css'`` file with this content:
|
||||||
|
|
||||||
@import url("../admin/css/base.27e20196a850.css");
|
@import url("../admin/css/base.27e20196a850.css");
|
||||||
|
|
||||||
|
You can change the location of the manifest file by using a custom
|
||||||
|
``ManifestStaticFilesStorage`` subclass that sets the ``manifest_storage``
|
||||||
|
argument. For example::
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.staticfiles.storage import (
|
||||||
|
ManifestStaticFilesStorage, StaticFilesStorage,
|
||||||
|
)
|
||||||
|
|
||||||
|
class MyManifestStaticFilesStorage(ManifestStaticFilesStorage):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
manifest_storage = StaticFilesStorage(location=settings.BASE_DIR)
|
||||||
|
super().__init__(*args, manifest_storage=manifest_storage, **kwargs)
|
||||||
|
|
||||||
.. versionchanged:: 4.0
|
.. versionchanged:: 4.0
|
||||||
|
|
||||||
Support for finding paths in the source map comments was added.
|
Support for finding paths in the source map comments was added.
|
||||||
|
@ -320,6 +334,8 @@ For example, the ``'css/styles.css'`` file with this content:
|
||||||
Support for finding paths to JavaScript modules in ``import`` and
|
Support for finding paths to JavaScript modules in ``import`` and
|
||||||
``export`` statements was added.
|
``export`` statements was added.
|
||||||
|
|
||||||
|
The ``manifest_storage`` argument was added.
|
||||||
|
|
||||||
.. attribute:: storage.ManifestStaticFilesStorage.max_post_process_passes
|
.. attribute:: storage.ManifestStaticFilesStorage.max_post_process_passes
|
||||||
|
|
||||||
Since static files might reference other static files that need to have their
|
Since static files might reference other static files that need to have their
|
||||||
|
@ -384,6 +400,10 @@ hashing algorithm.
|
||||||
Use this mixin with a custom storage to append the MD5 hash of the file's
|
Use this mixin with a custom storage to append the MD5 hash of the file's
|
||||||
content to the filename as :class:`~storage.ManifestStaticFilesStorage` does.
|
content to the filename as :class:`~storage.ManifestStaticFilesStorage` does.
|
||||||
|
|
||||||
|
.. versionchanged:: 4.0
|
||||||
|
|
||||||
|
The ``manifest_storage`` argument was added.
|
||||||
|
|
||||||
Finders Module
|
Finders Module
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,11 @@ Minor features
|
||||||
replaces paths to JavaScript modules in ``import`` and ``export`` statements
|
replaces paths to JavaScript modules in ``import`` and ``export`` statements
|
||||||
with their hashed counterparts.
|
with their hashed counterparts.
|
||||||
|
|
||||||
|
* The new ``manifest_storage`` argument of
|
||||||
|
:class:`~django.contrib.staticfiles.storage.ManifestFilesMixin` and
|
||||||
|
:class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage`
|
||||||
|
allows customizing the manifest file storage.
|
||||||
|
|
||||||
:mod:`django.contrib.syndication`
|
:mod:`django.contrib.syndication`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
@ -13,7 +14,7 @@ from django.contrib.staticfiles.management.commands.collectstatic import (
|
||||||
Command as CollectstaticCommand,
|
Command as CollectstaticCommand,
|
||||||
)
|
)
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.test import override_settings
|
from django.test import SimpleTestCase, override_settings
|
||||||
|
|
||||||
from .cases import CollectionTestCase
|
from .cases import CollectionTestCase
|
||||||
from .settings import TEST_ROOT
|
from .settings import TEST_ROOT
|
||||||
|
@ -499,6 +500,55 @@ class TestCollectionSimpleStorage(CollectionTestCase):
|
||||||
self.assertIn(b"other.deploy12345.css", content)
|
self.assertIn(b"other.deploy12345.css", content)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomManifestStorage(storage.ManifestStaticFilesStorage):
|
||||||
|
def __init__(self, *args, manifest_storage=None, **kwargs):
|
||||||
|
manifest_storage = storage.StaticFilesStorage(
|
||||||
|
location=kwargs.pop('manifest_location'),
|
||||||
|
)
|
||||||
|
super().__init__(*args, manifest_storage=manifest_storage, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCustomManifestStorage(SimpleTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.manifest_path = Path(tempfile.mkdtemp())
|
||||||
|
self.addCleanup(shutil.rmtree, self.manifest_path)
|
||||||
|
|
||||||
|
self.staticfiles_storage = CustomManifestStorage(
|
||||||
|
manifest_location=self.manifest_path,
|
||||||
|
)
|
||||||
|
self.manifest_file = self.manifest_path / self.staticfiles_storage.manifest_name
|
||||||
|
# Manifest without paths.
|
||||||
|
self.manifest = {'version': self.staticfiles_storage.manifest_version}
|
||||||
|
with self.manifest_file.open('w') as manifest_file:
|
||||||
|
json.dump(self.manifest, manifest_file)
|
||||||
|
|
||||||
|
def test_read_manifest(self):
|
||||||
|
self.assertEqual(
|
||||||
|
self.staticfiles_storage.read_manifest(),
|
||||||
|
json.dumps(self.manifest),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_read_manifest_nonexistent(self):
|
||||||
|
os.remove(self.manifest_file)
|
||||||
|
self.assertIsNone(self.staticfiles_storage.read_manifest())
|
||||||
|
|
||||||
|
def test_save_manifest_override(self):
|
||||||
|
self.assertIs(self.manifest_file.exists(), True)
|
||||||
|
self.staticfiles_storage.save_manifest()
|
||||||
|
self.assertIs(self.manifest_file.exists(), True)
|
||||||
|
new_manifest = json.loads(self.staticfiles_storage.read_manifest())
|
||||||
|
self.assertIn('paths', new_manifest)
|
||||||
|
self.assertNotEqual(new_manifest, self.manifest)
|
||||||
|
|
||||||
|
def test_save_manifest_create(self):
|
||||||
|
os.remove(self.manifest_file)
|
||||||
|
self.staticfiles_storage.save_manifest()
|
||||||
|
self.assertIs(self.manifest_file.exists(), True)
|
||||||
|
new_manifest = json.loads(self.staticfiles_storage.read_manifest())
|
||||||
|
self.assertIn('paths', new_manifest)
|
||||||
|
self.assertNotEqual(new_manifest, self.manifest)
|
||||||
|
|
||||||
|
|
||||||
class CustomStaticFilesStorage(storage.StaticFilesStorage):
|
class CustomStaticFilesStorage(storage.StaticFilesStorage):
|
||||||
"""
|
"""
|
||||||
Used in TestStaticFilePermissions
|
Used in TestStaticFilePermissions
|
||||||
|
|
Loading…
Reference in New Issue