summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorth3hamm0r <stefan.hammer@wunderweiss.com>2022-05-27 14:45:20 +0200
committerGitHub <noreply@github.com>2022-05-27 14:45:20 +0200
commitd70f1d6cc8696386afa8590ba8e6f269658f112d (patch)
tree8415ee085f5481ddf8df4a1a6070f385d06281ec
parent219b00b7375d2531f4c8f8e8f3b84ddcf48c673c (diff)
downloaddjango-compressor-d70f1d6cc8696386afa8590ba8e6f269658f112d.tar.gz
Implement separate storage for the offline manifest
* Implement separate storage for the offline manifest, fixes #1112 * correctly use urljoin() for URLs; added example to docs * Updated changelog
-rw-r--r--compressor/cache.py16
-rw-r--r--compressor/conf.py1
-rw-r--r--compressor/storage.py18
-rw-r--r--compressor/tests/test_offline.py14
-rw-r--r--compressor/tests/test_storages.py6
-rw-r--r--docs/changelog.txt10
-rw-r--r--docs/settings.txt23
7 files changed, 70 insertions, 18 deletions
diff --git a/compressor/cache.py b/compressor/cache.py
index d04a924..6152357 100644
--- a/compressor/cache.py
+++ b/compressor/cache.py
@@ -11,7 +11,7 @@ from django.utils.encoding import force_str, smart_bytes
from django.utils.functional import SimpleLazyObject
from compressor.conf import settings
-from compressor.storage import default_storage
+from compressor.storage import default_offline_manifest_storage
from compressor.utils import get_mod_func
_cachekey_func = None
@@ -66,20 +66,15 @@ def get_offline_cachekey(source):
return get_cachekey("offline.%s" % get_offline_hexdigest(source))
-def get_offline_manifest_filename():
- output_dir = settings.COMPRESS_OUTPUT_DIR.strip('/')
- return os.path.join(output_dir, settings.COMPRESS_OFFLINE_MANIFEST)
-
-
_offline_manifest = None
def get_offline_manifest():
global _offline_manifest
if _offline_manifest is None:
- filename = get_offline_manifest_filename()
- if default_storage.exists(filename):
- with default_storage.open(filename) as fp:
+ filename = settings.COMPRESS_OFFLINE_MANIFEST
+ if default_offline_manifest_storage.exists(filename):
+ with default_offline_manifest_storage.open(filename) as fp:
_offline_manifest = json.loads(fp.read().decode('utf8'))
else:
_offline_manifest = {}
@@ -92,9 +87,8 @@ def flush_offline_manifest():
def write_offline_manifest(manifest):
- filename = get_offline_manifest_filename()
content = json.dumps(manifest, indent=2).encode('utf8')
- default_storage.save(filename, ContentFile(content))
+ default_offline_manifest_storage.save(settings.COMPRESS_OFFLINE_MANIFEST, ContentFile(content))
flush_offline_manifest()
diff --git a/compressor/conf.py b/compressor/conf.py
index 9a2d158..7ebdbae 100644
--- a/compressor/conf.py
+++ b/compressor/conf.py
@@ -75,6 +75,7 @@ class CompressorConf(AppConf):
OFFLINE_CONTEXT = {}
# The name of the manifest file (e.g. filename.ext)
OFFLINE_MANIFEST = 'manifest.json'
+ OFFLINE_MANIFEST_STORAGE = 'compressor.storage.OfflineManifestFileStorage'
# The Context to be used when TemplateFilter is used
TEMPLATE_FILTER_CONTEXT = {}
# Placeholder to be used instead of settings.COMPRESS_URL during offline compression.
diff --git a/compressor/storage.py b/compressor/storage.py
index 5d12eb8..1bf58dd 100644
--- a/compressor/storage.py
+++ b/compressor/storage.py
@@ -2,6 +2,7 @@ import gzip
import os
from datetime import datetime
import time
+from urllib.parse import urljoin
from django.core.files.storage import FileSystemStorage, get_storage_class
from django.utils.functional import LazyObject, SimpleLazyObject
@@ -110,3 +111,20 @@ class DefaultStorage(LazyObject):
default_storage = DefaultStorage()
+
+
+class OfflineManifestFileStorage(CompressorFileStorage):
+ def __init__(self, location=None, base_url=None, *args, **kwargs):
+ if location is None:
+ location = os.path.join(settings.COMPRESS_ROOT, settings.COMPRESS_OUTPUT_DIR)
+ if base_url is None:
+ base_url = urljoin(settings.COMPRESS_URL, settings.COMPRESS_OUTPUT_DIR)
+ super().__init__(location, base_url, *args, **kwargs)
+
+
+class DefaultOfflineManifestStorage(LazyObject):
+ def _setup(self):
+ self._wrapped = get_storage_class(settings.COMPRESS_OFFLINE_MANIFEST_STORAGE)()
+
+
+default_offline_manifest_storage = DefaultOfflineManifestStorage()
diff --git a/compressor/tests/test_offline.py b/compressor/tests/test_offline.py
index 6936377..b7ff0fa 100644
--- a/compressor/tests/test_offline.py
+++ b/compressor/tests/test_offline.py
@@ -15,7 +15,7 @@ from django.urls import get_script_prefix, set_script_prefix
from compressor.cache import flush_offline_manifest, get_offline_manifest
from compressor.exceptions import OfflineGenerationError
from compressor.management.commands.compress import Command as CompressCommand
-from compressor.storage import default_storage
+from compressor.storage import default_offline_manifest_storage
from compressor.utils import get_mod_func
@@ -154,9 +154,9 @@ class OfflineTestCaseMixin:
def tearDown(self):
self.override_settings.__exit__(None, None, None)
- manifest_path = os.path.join('CACHE', 'manifest.json')
- if default_storage.exists(manifest_path):
- default_storage.delete(manifest_path)
+ manifest_filename = 'manifest.json'
+ if default_offline_manifest_storage.exists(manifest_filename):
+ default_offline_manifest_storage.delete(manifest_filename)
def _prepare_contexts(self, engine):
contexts = settings.COMPRESS_OFFLINE_CONTEXT
@@ -311,9 +311,9 @@ class OfflineCompressBasicTestCase(OfflineTestCaseMixin, TestCase):
def _test_deleting_manifest_does_not_affect_rendering(self, engine):
count, result = CompressCommand().handle_inner(engines=[engine], verbosity=0)
get_offline_manifest()
- manifest_path = os.path.join('CACHE', 'manifest.json')
- if default_storage.exists(manifest_path):
- default_storage.delete(manifest_path)
+ manifest_filename = 'manifest.json'
+ if default_offline_manifest_storage.exists(manifest_filename):
+ default_offline_manifest_storage.delete(manifest_filename)
self.assertEqual(1, count)
self.assertEqual([self._render_script(self.expected_hash)], result)
rendered_template = self._render_template(engine)
diff --git a/compressor/tests/test_storages.py b/compressor/tests/test_storages.py
index 9168510..112c250 100644
--- a/compressor/tests/test_storages.py
+++ b/compressor/tests/test_storages.py
@@ -67,3 +67,9 @@ class StorageTestCase(TestCase):
filename2 = self.default_storage.save('test.txt', ContentFile('yeah yeah'))
self.assertEqual(filename1, filename2)
self.assertNotIn("_", filename2)
+
+ def test_offline_manifest_storage(self):
+ storage.default_offline_manifest_storage.save('test.txt', ContentFile('yeah yeah'))
+ self.assertTrue(os.path.exists(os.path.join(settings.COMPRESS_ROOT, 'CACHE', 'test.txt')))
+ # Check that the file is stored at the same default location as before the new manifest storage.
+ self.assertTrue(self.default_storage.exists(os.path.join('CACHE', 'test.txt')))
diff --git a/docs/changelog.txt b/docs/changelog.txt
index 0f1a447..420906f 100644
--- a/docs/changelog.txt
+++ b/docs/changelog.txt
@@ -1,6 +1,16 @@
Changelog
=========
+Unreleased
+----------
+
+- New setting ``COMPRESS_OFFLINE_MANIFEST_STORAGE`` to customize the offline manifest's file storage (#1112)
+
+ With this change the function ``compressor.cache.get_offline_manifest_filename()`` has been removed.
+ You can now use the new file storage ``compressor.storage.default_offline_manifest_storage`` to access the
+ location of the manifest.
+
+
v4.0 (2022-03-23)
-----------------
diff --git a/docs/settings.txt b/docs/settings.txt
index 7b65b66..c2ab048 100644
--- a/docs/settings.txt
+++ b/docs/settings.txt
@@ -541,3 +541,26 @@ Offline settings
The name of the file to be used for saving the names of the files
compressed offline.
+
+.. attribute:: COMPRESS_OFFLINE_MANIFEST_STORAGE
+
+ :Default: ``compressor.storage.OfflineManifestFileStorage``
+
+ The dotted path to a Django Storage backend to be used to save the
+ offline manifest.
+
+ By default, the file configured with
+ :attr:`~django.conf.settings.COMPRESS_OFFLINE_MANIFEST` will be stored
+ into :attr:`~django.conf.settings.COMPRESS_OUTPUT_DIR`.
+
+ An example to output the manifest into the project's root directory::
+
+ # project/settings.py:
+ COMPRESS_STORAGE = 'project.module.PrivateOfflineManifestFileStorage'
+
+ # project/module.py:
+ from compressor.storage import OfflineManifestFileStorage
+ from django.conf import settings
+ class PrivateOfflineManifestFileStorage(OfflineManifestFileStorage):
+ def __init__(self, *args, **kwargs):
+ super().__init__(settings.BASE_DIR, None, *args, **kwargs)