Skip to content

Commit d5a6810

Browse files
committed
Merge branch 'master' of github.com:jazzband/django-pipeline
2 parents 21efb5c + 930b12c commit d5a6810

File tree

13 files changed

+263
-26
lines changed

13 files changed

+263
-26
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ or just made Pipeline more awesome.
7676
* Mike Gilbert <[email protected]>
7777
* Miroslav Shubernetskiy <[email protected]>
7878
* Natal Ngetal <[email protected]>
79+
* Nathan Cox <[email protected]>
7980
* Nathan Shafer <[email protected]>
8081
* Patrick Altman <[email protected]>
8182
* Peter Baumgartner <[email protected]>

HISTORY.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@
33
History
44
=======
55

6+
1.6.7
7+
=====
8+
9+
* Add a view for collecting static files before serving them. This behaves like
10+
django's built-in ``static`` view and allows running the collector for
11+
images, fonts, and other static files that do not need to be compiled. Thanks
12+
to Christian Hammond.
13+
* Update documentation for the ES6Compiler to clarify filename requirements.
14+
Thanks to Nathan Cox.
15+
* Add error output for compiler errors within the browser. This provides for a
16+
much better experience when compiling files from the devserver. Thanks to
17+
Christian Hammond.
18+
* Make unit tests run against Django 1.6 and 1.7. Thanks to Sławek Ehlert.
19+
620
1.6.6
721
=====
822

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ Documentation
2626
-------------
2727

2828
For documentation, usage, and examples, see :
29-
http://django-pipeline.readthedocs.org
29+
https://django-pipeline.readthedocs.org

docs/compilers.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,14 @@ ES6 compiler
150150
The ES6 compiler uses `Babel <https://babeljs.io>`_
151151
to convert ES6+ code into vanilla ES5.
152152

153+
Note that for files to be transpiled properly they must have the file extension **.es6**
154+
153155
To use it add this to your ``PIPELINE['COMPILERS']`` ::
154156

155157
PIPELINE['COMPILERS'] = (
156158
'pipeline.compilers.es6.ES6Compiler',
157159
)
158-
160+
159161

160162
``BABEL_BINARY``
161163
--------------------------

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
# The short X.Y version.
5252
version = '1.6'
5353
# The full version, including alpha/beta/rc tags.
54-
release = '1.6.6'
54+
release = '1.6.7'
5555

5656
# The language for content autogenerated by Sphinx. Refer to documentation
5757
# for a list of supported languages.

pipeline/collector.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from django.contrib.staticfiles import finders
88
from django.contrib.staticfiles.storage import staticfiles_storage
9+
from django.utils import six
910

1011
from pipeline.finders import PipelineFinder
1112

@@ -26,7 +27,7 @@ def clear(self, path=""):
2627
for d in dirs:
2728
self.clear(os.path.join(path, d))
2829

29-
def collect(self, request=None):
30+
def collect(self, request=None, files=[]):
3031
if self.request and self.request is request:
3132
return
3233
self.request = request
@@ -41,10 +42,17 @@ def collect(self, request=None):
4142
prefixed_path = os.path.join(storage.prefix, path)
4243
else:
4344
prefixed_path = path
44-
if prefixed_path not in found_files:
45+
46+
if (prefixed_path not in found_files and
47+
(not files or prefixed_path in files)):
4548
found_files[prefixed_path] = (storage, path)
4649
self.copy_file(path, prefixed_path, storage)
4750

51+
if files and len(files) == len(found_files):
52+
break
53+
54+
return six.iterkeys(found_files)
55+
4856
def copy_file(self, path, prefixed_path, source_storage):
4957
# Delete the target file if needed or break
5058
if not self.delete_file(path, prefixed_path, source_storage):

pipeline/compilers/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,12 @@ def output_path(self, path, extension):
7979
return '.'.join((path[0], extension))
8080

8181
def is_outdated(self, infile, outfile):
82-
if not self.storage.exists(outfile):
82+
if not os.path.exists(outfile):
8383
return True
84+
8485
try:
85-
return self.storage.modified_time(infile) > self.storage.modified_time(outfile)
86-
except (OSError, NotImplementedError):
86+
return os.path.getmtime(infile) > os.path.getmtime(outfile)
87+
except OSError:
8788
return True
8889

8990

pipeline/templatetags/pipeline.py

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,29 +54,66 @@ def render(self, context):
5454
pass
5555

5656
def render_compressed(self, package, package_name, package_type):
57+
"""Render HTML for the package.
58+
59+
If ``PIPELINE_ENABLED`` is ``True``, this will render the package's
60+
output file (using :py:meth:`render_compressed_output`). Otherwise,
61+
this will render the package's source files (using
62+
:py:meth:`render_compressed_sources`).
63+
64+
Subclasses can override this method to provide custom behavior for
65+
determining what to render.
66+
"""
5767
if settings.PIPELINE_ENABLED:
58-
method = getattr(self, "render_{0}".format(package_type))
59-
return method(package, package.output_filename)
68+
return self.render_compressed_output(package, package_name,
69+
package_type)
6070
else:
61-
if settings.PIPELINE_COLLECTOR_ENABLED:
62-
default_collector.collect(self.request)
71+
return self.render_compressed_sources(package, package_name,
72+
package_type)
73+
74+
def render_compressed_output(self, package, package_name, package_type):
75+
"""Render HTML for using the package's output file.
76+
77+
Subclasses can override this method to provide custom behavior for
78+
rendering the output file.
79+
"""
80+
method = getattr(self, 'render_{0}'.format(package_type))
81+
82+
return method(package, package.output_filename)
83+
84+
def render_compressed_sources(self, package, package_name, package_type):
85+
"""Render HTML for using the package's list of source files.
6386
64-
packager = Packager()
65-
method = getattr(self, "render_individual_{0}".format(package_type))
87+
Each source file will first be collected, if
88+
``PIPELINE_COLLECTOR_ENABLED`` is ``True``.
89+
90+
If there are any errors compiling any of the source files, an
91+
``SHOW_ERRORS_INLINE`` is ``True``, those errors will be shown at
92+
the top of the page.
93+
94+
Subclasses can override this method to provide custom behavior for
95+
rendering the source files.
96+
"""
97+
if settings.PIPELINE_COLLECTOR_ENABLED:
98+
default_collector.collect(self.request)
99+
100+
packager = Packager()
101+
method = getattr(self, 'render_individual_{0}'.format(package_type))
102+
103+
try:
104+
paths = packager.compile(package.paths)
105+
except CompilerError as e:
106+
if settings.SHOW_ERRORS_INLINE:
107+
method = getattr(self, 'render_error_{0}'.format(
108+
package_type))
66109

67-
try:
68-
paths = packager.compile(package.paths)
69-
except CompilerError as e:
70-
if settings.SHOW_ERRORS_INLINE:
71-
method = getattr(self, 'render_error_{0}'.format(
72-
package_type))
110+
return method(package_name, e)
111+
else:
112+
raise
73113

74-
return method(package_name, e)
75-
else:
76-
raise
114+
templates = packager.pack_templates(package)
77115

78-
templates = packager.pack_templates(package)
79-
return method(package, paths, templates=templates)
116+
return method(package, paths, templates=templates)
80117

81118
def render_error(self, package_type, package_name, e):
82119
return render_to_string('pipeline/compile_error.html', Context({

pipeline/views.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from __future__ import unicode_literals
2+
3+
from django.conf import settings as django_settings
4+
from django.core.exceptions import ImproperlyConfigured
5+
from django.views.static import serve
6+
7+
from .collector import default_collector
8+
from .conf import settings
9+
10+
11+
def serve_static(request, path, insecure=False, **kwargs):
12+
"""Collect and serve static files.
13+
14+
This view serves up static files, much like Django's
15+
:py:func:`~django.views.static.serve` view, with the addition that it
16+
collects static files first (if enabled). This allows images, fonts, and
17+
other assets to be served up without first loading a page using the
18+
``{% javascript %}`` or ``{% stylesheet %}`` template tags.
19+
20+
You can use this view by adding the following to any :file:`urls.py`::
21+
22+
urlpatterns += static('static/', view='pipeline.views.serve_static')
23+
"""
24+
# Follow the same logic Django uses for determining access to the
25+
# static-serving view.
26+
if not django_settings.DEBUG and not insecure:
27+
raise ImproperlyConfigured("The staticfiles view can only be used in "
28+
"debug mode or if the --insecure "
29+
"option of 'runserver' is used")
30+
31+
if not settings.PIPELINE_ENABLED and settings.PIPELINE_COLLECTOR_ENABLED:
32+
# Collect only the requested file, in order to serve the result as
33+
# fast as possible. This won't interfere with the template tags in any
34+
# way, as those will still cause Django to collect all media.
35+
default_collector.collect(request, files=[path])
36+
37+
return serve(request, path, document_root=django_settings.STATIC_ROOT,
38+
**kwargs)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
setup(
1212
name='django-pipeline',
13-
version='1.6.6',
13+
version='1.6.7',
1414
description='Pipeline is an asset packaging library for Django.',
1515
long_description=io.open('README.rst', encoding='utf-8').read() + '\n\n' +
1616
io.open('HISTORY.rst', encoding='utf-8').read(),

0 commit comments

Comments
 (0)