File operations always raise a ENOENT error when a file doesn't exist.
Checking the file exists before the operation adds a race condition
condition where the file could be removed between operations. As the
operation already raises an error on a missing file, avoid this race and
avoid checking the file exists twice. Instead only check a file exists
by catching the ENOENT error.
New Storage.get_{accessed,created,modified}_time() methods convert the
naive time from now-deprecated {accessed,created_modified}_time()
methods into aware objects in UTC if USE_TZ=True.
When running collectstatic with a hashing static file storage backend,
URLs referencing other files were normalized with posixpath.normpath.
This could corrupt URLs: for example 'a.css#b/../c' became just 'c'.
Normalization seems to be an artifact of the historical implementation.
It contained a home-grown implementation of posixpath.join which relied
on counting occurrences of .. and /, so multiple / had to be collapsed.
The new implementation introduced in the previous commit doesn't suffer
from this issue. So it seems safe to remove the normalization.
There was a test for this normalization behavior but I don't think it's
a good test. Django shouldn't modify CSS that way. If a developer has
rendundant /s, it's mostly an aesthetic issue and it isn't Django's job
to fix it. Conversely, if the user wants a series of /s, perhaps in the
URL fragment, Django shouldn't destroy it.
Refs #26249.
collectstatic crashed when:
* a hashing static file storage backend was used
* a static file referenced another static file located directly in
STATIC_ROOT (not a subdirectory) with an absolute URL (which must
start with STATIC_URL, which cannot be empty)
It seems to me that the current code reimplements relative path joining
and doesn't handle edge cases correctly. I suspect it assumes that
STATIC_URL is of the form r'/[^/]+/'.
Throwing out that code in favor of the posixpath module makes the logic
easier to follow. Handling absolute paths correctly also becomes easier.
Before cf546e1, static files in form or widget Media were usually
wrapped with contrib.staticfiles.templatetags.staticfiles.static.
This test ensures compatibility with third-party code that's still
using this pattern.
A @font-face declaration may contain a fragment that looks like a relative path,
e.g. @font-face { src: url('../fonts/font.svg#../path/like/fragment'); }
In this case, an incorrect path was passed to the storage backend, which raised
an error that caused collectstatic to crash.
This requires that each test never alters files in static directories
collected by other tests. The alternative is to add a temporary
directory to STATICFILES_DIRS or a new app to INSTALLED_APPS.