Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions src/webassets/bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ def _make_output_url(self, ctx):
url = "%s?%s" % (url, version)
return url

def _urls(self, ctx, extra_filters, *args, **kwargs):
def _urls(self, ctx, extra_filters, with_bodies, *args, **kwargs):
"""Return a list of urls for this bundle, and all subbundles,
and, when it becomes necessary, start a build process.
"""
Expand Down Expand Up @@ -744,7 +744,13 @@ def _urls(self, ctx, extra_filters, *args, **kwargs):
if ctx.auto_build:
self._build(ctx, extra_filters=extra_filters, force=False,
*args, **kwargs)
return [self._make_output_url(ctx)]
if with_bodies:
# The hunks returned by the _build() method aren't useful as
# they sometimes have %(version)s in them. Can this be changed?
hunk = FileHunk(self.resolve_output(ctx))
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That amazing work, thanks a bunch for putting in the time. Unfortunately, I think we have a problem here that is possibly complex, which is that before this patch, you could set auto_build to False, and the correct urls could be generated without the filesystem being touched; indeed, the actual files needn't be available. That's incredibly useful for when your static files are on S3 or the like, or if you just want to avoid the performance hit.

Of course, if ASSETS_CONTENT is used, that is no longer possible. We can also ignore the question whether webassets should cache the content in memory for now; but the problem is that right now, by always using urls_with_content in the template tag, unless I am mistaken, you are essentially forcing a file read in all cases.

Ideally, the tag could detect the presence of ASSETS_CONTENT itself. I'm not sure if that is possible.

return [(self._make_output_url(ctx), hunk.data())]
else:
return [self._make_output_url(ctx)]
else:
# We either have no files (nothing to build), or we are
# in debug mode: Instead of building the bundle, we
Expand All @@ -755,10 +761,15 @@ def _urls(self, ctx, extra_filters, *args, **kwargs):
urls.extend(org._urls(
wrap(ctx, cnt),
merge_filters(extra_filters, self.filters),
with_bodies,
*args, **kwargs))
elif is_url(cnt):
urls.append(cnt)
if with_bodies:
urls.append((cnt, UrlHunk(cnt, ctx).data()))
else:
urls.append(cnt)
else:
external = None
try:
url = ctx.resolver.resolve_source_to_url(ctx, cnt, org)
except ValueError:
Expand All @@ -768,7 +779,10 @@ def _urls(self, ctx, extra_filters, *args, **kwargs):
external = pull_external(ctx, cnt)
url = ctx.resolver.resolve_source_to_url(ctx, external, org)

urls.append(url)
if with_bodies:
urls.append((url, FileHunk(external or cnt).data()))
else:
urls.append(url)
return urls

def urls(self, *args, **kwargs):
Expand All @@ -784,9 +798,21 @@ def urls(self, *args, **kwargs):
ctx = wrap(self.env, self)
urls = []
for bundle, extra_filters, new_ctx in self.iterbuild(ctx):
urls.extend(bundle._urls(new_ctx, extra_filters, *args, **kwargs))
urls.extend(bundle._urls(new_ctx, extra_filters, False, *args, **kwargs))
return urls

def urls_with_bodies(self, *args, **kwargs):
"""Returns a list of tuples containing urls and their content.

Works just like urls() except that it returns tuples of the urls
and their respective content.
"""
ctx = wrap(self.env, self)
urls_contents = []
for bundle, extra_filters, new_ctx in self.iterbuild(ctx):
urls_contents.extend(bundle._urls(new_ctx, extra_filters, True, *args, **kwargs))
return urls_contents


def pull_external(ctx, filename):
"""Helper which will pull ``filename`` into
Expand Down
7 changes: 4 additions & 3 deletions src/webassets/ext/jinja2.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ def parse(self, parser):
#
# Summary: We have to be satisfied with a single EXTRA variable.
args = [nodes.Name('ASSET_URL', 'store'),
nodes.Name('ASSET_CONTENTS', 'store'),
nodes.Name('EXTRA', 'store')]

# Return a ``CallBlock``, which means Jinja2 will call a Python method
Expand Down Expand Up @@ -183,13 +184,13 @@ def _render_assets(self, filter, output, dbg, depends, files, caller=None):

# Retrieve urls (this may or may not cause a build)
with bundle.bind(env):
urls = bundle.urls()
urls = bundle.urls_with_bodies()

# For each url, execute the content of this template tag (represented
# by the macro ```caller`` given to use by Jinja2).
result = u""
for url in urls:
result += caller(url, bundle.extra)
for url, body in urls:
result += caller(url, body, bundle.extra)
return result


Expand Down
10 changes: 10 additions & 0 deletions tests/test_ext/test_jinja2.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def setup(self):
test_instance = self
class MockBundle(Bundle):
urls_to_fake = ['foo']
content_to_fake = ['bar']
def __init__(self, *a, **kw):
Bundle.__init__(self, *a, **kw)
self.env = assets_env
Expand All @@ -38,6 +39,9 @@ def __init__(self, *a, **kw):
test_instance.the_bundle = self
def urls(self, *a, **kw):
return self.urls_to_fake
def urls_with_bodies(self, *a, **kw):
return zip(self.urls_to_fake, self.content_to_fake)

self._old_bundle_class = AssetsExtension.BundleClass
AssetsExtension.BundleClass = self.BundleClass = MockBundle

Expand Down Expand Up @@ -87,8 +91,14 @@ def test_output_urls(self):
"""Ensure the tag correctly spits out the urls the bundle returns.
"""
self.BundleClass.urls_to_fake = ['foo', 'bar']
self.BundleClass.content_to_fake = ['as', 'df']
assert self.render_template('"file1" "file2" "file3"') == 'foo;bar;'

def test_asset_contents(self):
output = self.jinja_env.from_string(
'{% assets "bundle" %}{{ ASSET_CONTENTS }}{% endassets %}').render({})
assert output == 'bar'

def test_debug_on_tag(self):
content = self.jinja_env.from_string(
'{% assets debug="True", "debug1.txt" %}{{ ASSET_URL }};{% endassets %}').render({})
Expand Down