Commit 12b09b7a by Timothée Peignier

rewrite assets url as relative url rather than absolute. close #79

parent 35eeaba7
...@@ -92,21 +92,6 @@ Group options ...@@ -92,21 +92,6 @@ Group options
For CSS, if you do not specify ``extra_context``/``media``, the default media in For CSS, if you do not specify ``extra_context``/``media``, the default media in
the ``<link>`` output will be ``media="all"``. the ``<link>`` output will be ``media="all"``.
``absolute_paths``
........................
**Optional**
Indicates if relative paths in CSS files should be made absolute, based on
``PIPELINE_URL``. This only applies to entries in ``PIPELINE_CSS``.
Defaults to ``True``.
.. note::
Note that all filenames are specified relative to ``PIPELINE_ROOT``, and thus the source
files needs to be in your ``PIPELINE_ROOT``.
``manifest`` ``manifest``
............ ............
......
import os import os
import subprocess import subprocess
try:
from staticfiles import finders
except ImportError:
from django.contrib.staticfiles import finders # noqa
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
...@@ -26,7 +31,7 @@ class Compiler(object): ...@@ -26,7 +31,7 @@ class Compiler(object):
new_path = self.output_path(path, compiler.output_extension) new_path = self.output_path(path, compiler.output_extension)
content = self.read_file(path) content = self.read_file(path)
try: try:
compiled_content = compiler.compile_file(content, self.storage.path(path)) compiled_content = compiler.compile_file(content, finders.find(path))
self.save_file(new_path, compiled_content) self.save_file(new_path, compiled_content)
except CompilerError: except CompilerError:
if not self.storage.exists(new_path) or not settings.PIPELINE: if not self.storage.exists(new_path) or not settings.PIPELINE:
......
...@@ -5,8 +5,13 @@ import subprocess ...@@ -5,8 +5,13 @@ import subprocess
from itertools import takewhile from itertools import takewhile
try:
from staticfiles import finders
except ImportError:
from django.contrib.staticfiles import finders # noqa
from pipeline.conf import settings from pipeline.conf import settings
from pipeline.utils import to_class, relpath from pipeline.utils import to_class
from pipeline.storage import default_storage from pipeline.storage import default_storage
MAX_IMAGE_SIZE = 32700 MAX_IMAGE_SIZE = 32700
...@@ -61,10 +66,9 @@ class Compressor(object): ...@@ -61,10 +66,9 @@ class Compressor(object):
return js return js
def compress_css(self, paths, variant=None, absolute_paths=True, **kwargs): def compress_css(self, paths, output_filename, variant=None, **kwargs):
"""Concatenate and compress CSS files""" """Concatenate and compress CSS files"""
css = self.concatenate_and_rewrite(paths, variant, css = self.concatenate_and_rewrite(paths, output_filename, variant)
absolute_paths)
compressor = self.css_compressor compressor = self.css_compressor
if compressor: if compressor:
css = getattr(compressor(verbose=self.verbose), 'compress_css')(css) css = getattr(compressor(verbose=self.verbose), 'compress_css')(css)
...@@ -116,7 +120,7 @@ class Compressor(object): ...@@ -116,7 +120,7 @@ class Compressor(object):
), r"\1", path) ), r"\1", path)
return re.sub(r"[\/\\]", "_", name) return re.sub(r"[\/\\]", "_", name)
def concatenate_and_rewrite(self, paths, variant=None, absolute_paths=True): def concatenate_and_rewrite(self, paths, output_filename, variant=None):
"""Concatenate together files and rewrite urls""" """Concatenate together files and rewrite urls"""
stylesheets = [] stylesheets = []
for path in paths: for path in paths:
...@@ -125,7 +129,7 @@ class Compressor(object): ...@@ -125,7 +129,7 @@ class Compressor(object):
if asset_path.startswith("http") or asset_path.startswith("//"): if asset_path.startswith("http") or asset_path.startswith("//"):
return "url(%s)" % asset_path return "url(%s)" % asset_path
asset_url = self.construct_asset_path(asset_path, path, asset_url = self.construct_asset_path(asset_path, path,
variant, absolute_paths) output_filename, variant)
return "url(%s)" % asset_url return "url(%s)" % asset_url
content = self.read_file(path) content = self.read_file(path)
content = re.sub(URL_DETECTOR, reconstruct, content) content = re.sub(URL_DETECTOR, reconstruct, content)
...@@ -136,16 +140,14 @@ class Compressor(object): ...@@ -136,16 +140,14 @@ class Compressor(object):
"""Concatenate together a list of files""" """Concatenate together a list of files"""
return '\n'.join([self.read_file(path) for path in paths]) return '\n'.join([self.read_file(path) for path in paths])
def construct_asset_path(self, asset_path, css_path, variant=None, absolute_paths=True): def construct_asset_path(self, asset_path, css_path, output_filename, variant=None):
"""Return a rewritten asset URL for a stylesheet""" """Return a rewritten asset URL for a stylesheet"""
public_path = self.absolute_path(asset_path, os.path.dirname(css_path)) public_path = self.absolute_path(asset_path, os.path.dirname(css_path))
if self.embeddable(public_path, variant): if self.embeddable(public_path, variant):
return "__EMBED__%s" % public_path return "__EMBED__%s" % public_path
if not absolute_paths:
return asset_path
if not os.path.isabs(asset_path): if not os.path.isabs(asset_path):
asset_path = self.relative_path(public_path) asset_path = self.relative_path(public_path, output_filename)
return asset_path[1:] return asset_path
def embeddable(self, path, variant): def embeddable(self, path, variant):
"""Is the asset embeddable ?""" """Is the asset embeddable ?"""
...@@ -193,10 +195,11 @@ class Compressor(object): ...@@ -193,10 +195,11 @@ class Compressor(object):
path = os.path.join(start, path) path = os.path.join(start, path)
return os.path.normpath(path) return os.path.normpath(path)
def relative_path(self, absolute_path): def relative_path(self, absolute_path, output_filename):
"""Rewrite paths relative to the output stylesheet path""" """Rewrite paths relative to the output stylesheet path"""
absolute_path = self.absolute_path(absolute_path, default_storage.location) absolute_path = os.path.join(settings.PIPELINE_ROOT, absolute_path)
return os.path.join(os.sep, relpath(absolute_path, default_storage.location)) output_path = os.path.join(settings.PIPELINE_ROOT, os.path.dirname(output_filename))
return os.path.relpath(absolute_path, output_path)
def read_file(self, path): def read_file(self, path):
"""Read file content in binary mode""" """Read file content in binary mode"""
......
...@@ -2,6 +2,7 @@ from django.conf import settings ...@@ -2,6 +2,7 @@ from django.conf import settings
PIPELINE = getattr(settings, 'PIPELINE', not settings.DEBUG) PIPELINE = getattr(settings, 'PIPELINE', not settings.DEBUG)
PIPELINE_ROOT = getattr(settings, 'PIPELINE_ROOT', settings.STATIC_URL)
PIPELINE_URL = getattr(settings, 'PIPELINE_URL', settings.STATIC_URL) PIPELINE_URL = getattr(settings, 'PIPELINE_URL', settings.STATIC_URL)
PIPELINE_STORAGE = getattr(settings, 'PIPELINE_STORAGE', PIPELINE_STORAGE = getattr(settings, 'PIPELINE_STORAGE',
......
...@@ -55,10 +55,6 @@ class Package(object): ...@@ -55,10 +55,6 @@ class Package(object):
def manifest(self): def manifest(self):
return self.config.get('manifest', True) return self.config.get('manifest', True)
@property
def absolute_paths(self):
return self.config.get('absolute_paths', True)
class Packager(object): class Packager(object):
def __init__(self, storage=default_storage, verbose=False, css_packages=None, js_packages=None): def __init__(self, storage=default_storage, verbose=False, css_packages=None, js_packages=None):
...@@ -90,8 +86,8 @@ class Packager(object): ...@@ -90,8 +86,8 @@ class Packager(object):
def pack_stylesheets(self, package, **kwargs): def pack_stylesheets(self, package, **kwargs):
return self.pack(package, self.compressor.compress_css, css_compressed, return self.pack(package, self.compressor.compress_css, css_compressed,
variant=package.variant, absolute_paths=package.absolute_paths, output_filename=package.output_filename,
**kwargs) variant=package.variant, **kwargs)
def compile(self, paths): def compile(self, paths):
return self.compiler.compile(paths) return self.compiler.compile(paths)
......
import os
import sys
import urllib import urllib
from django.utils import importlib from django.utils import importlib
...@@ -20,54 +18,3 @@ def filepath_to_uri(path): ...@@ -20,54 +18,3 @@ def filepath_to_uri(path):
if path is None: if path is None:
return path return path
return urllib.quote(smart_str(path).replace("\\", "/"), safe="/~!*()'#?") return urllib.quote(smart_str(path).replace("\\", "/"), safe="/~!*()'#?")
def _relpath_nt(path, start=os.path.curdir):
"""Return a relative version of a path"""
if not path:
raise ValueError("no path specified")
start_list = os.path.abspath(start).split(os.path.sep)
path_list = os.path.abspath(path).split(os.path.sep)
if start_list[0].lower() != path_list[0].lower():
unc_path, rest = os.path.splitunc(path)
unc_start, rest = os.path.splitunc(start)
if bool(unc_path) ^ bool(unc_start):
raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
% (path, start))
else:
raise ValueError("path is on drive %s, start on drive %s"
% (path_list[0], start_list[0]))
# Work out how much of the filepath is shared by start and path.
for i in range(min(len(start_list), len(path_list))):
if start_list[i].lower() != path_list[i].lower():
break
else:
i += 1
rel_list = [os.path.pardir] * (len(start_list) - i) + path_list[i:]
if not rel_list:
return os.path.curdir
return os.path.join(*rel_list)
def _relpath_posix(path, start=os.path.curdir):
"""Return a relative version of a path"""
if not path:
raise ValueError("no path specified")
start_list = os.path.abspath(start).split(os.path.sep)
path_list = os.path.abspath(path).split(os.path.sep)
# Work out how much of the filepath is shared by start and path.
i = len(os.path.commonprefix([start_list, path_list]))
rel_list = [os.path.pardir] * (len(start_list) - i) + path_list[i:]
if not rel_list:
return os.path.curdir
return os.path.join(*rel_list)
if os.path is sys.modules.get('ntpath'):
relpath = _relpath_nt
else:
relpath = _relpath_posix
...@@ -24,7 +24,7 @@ class CompressorTest(TestCase): ...@@ -24,7 +24,7 @@ class CompressorTest(TestCase):
css = self.compressor.concatenate_and_rewrite([ css = self.compressor.concatenate_and_rewrite([
'css/first.css', 'css/first.css',
'css/second.css' 'css/second.css'
]) ], 'css/screen.css')
self.assertEquals(""".concat {\n display: none;\n}\n\n.concatenate {\n display: block;\n}\n""", css) self.assertEquals(""".concat {\n display: none;\n}\n\n.concatenate {\n display: block;\n}\n""", css)
def test_concatenate(self): def test_concatenate(self):
...@@ -43,8 +43,8 @@ class CompressorTest(TestCase): ...@@ -43,8 +43,8 @@ class CompressorTest(TestCase):
self.assertFalse(mock.called) self.assertFalse(mock.called)
def test_relative_path(self): def test_relative_path(self):
relative_path = self.compressor.relative_path("%s/images/sprite.png" % storage.location) relative_path = self.compressor.relative_path("images/sprite.png", 'css/screen.css')
self.assertEquals(relative_path, '/images/sprite.png') self.assertEquals(relative_path, '../images/sprite.png')
def test_base_path(self): def test_base_path(self):
base_path = self.compressor.base_path([ base_path = self.compressor.base_path([
...@@ -87,39 +87,29 @@ class CompressorTest(TestCase): ...@@ -87,39 +87,29 @@ class CompressorTest(TestCase):
def test_construct_asset_path(self): def test_construct_asset_path(self):
asset_path = self.compressor.construct_asset_path("../../images/sprite.png", asset_path = self.compressor.construct_asset_path("../../images/sprite.png",
"css/plugins/gallery.css") "css/plugins/gallery.css", "css/gallery.css")
self.assertEquals(asset_path, "images/sprite.png") self.assertEquals(asset_path, "../images/sprite.png")
asset_path = self.compressor.construct_asset_path("/images/sprite.png", asset_path = self.compressor.construct_asset_path("/images/sprite.png",
"css/plugins/gallery.css") "css/plugins/gallery.css", "css/gallery.css")
self.assertEquals(asset_path, "images/sprite.png")
def test_construct_asset_path_relative(self):
asset_path = self.compressor.construct_asset_path("../../images/sprite.png",
"css/plugins/gallery.css",
absolute_paths=False)
self.assertEquals(asset_path, "../../images/sprite.png")
asset_path = self.compressor.construct_asset_path("/images/sprite.png",
"css/plugins/gallery.css",
absolute_paths=False)
self.assertEquals(asset_path, "/images/sprite.png") self.assertEquals(asset_path, "/images/sprite.png")
def test_url_rewrite(self): def test_url_rewrite(self):
output = self.compressor.concatenate_and_rewrite([ output = self.compressor.concatenate_and_rewrite([
'css/urls.css', 'css/urls.css',
]) ], 'css/screen.css')
self.assertEquals("""@font-face { self.assertEquals("""@font-face {
font-family: 'Pipeline'; font-family: 'Pipeline';
src: url(fonts/pipeline.eot); src: url(../fonts/pipeline.eot);
src: url(fonts/pipeline.eot?#iefix) format('embedded-opentype'); src: url(../fonts/pipeline.eot?#iefix) format('embedded-opentype');
src: local('☺'), url(fonts/pipeline.woff) format('woff'), url(fonts/pipeline.ttf) format('truetype'), url(fonts/pipeline.svg#IyfZbseF) format('svg'); src: local('☺'), url(../fonts/pipeline.woff) format('woff'), url(../fonts/pipeline.ttf) format('truetype'), url(../fonts/pipeline.svg#IyfZbseF) format('svg');
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }
.relative-url { .relative-url {
background-image: url(images/sprite-buttons.png); background-image: url(../images/sprite-buttons.png);
} }
.absolute-url { .absolute-url {
background-image: url(images/sprite-buttons.png); background-image: url(/images/sprite-buttons.png);
} }
.absolute-full-url { .absolute-full-url {
background-image: url(http://localhost/images/sprite-buttons.png); background-image: url(http://localhost/images/sprite-buttons.png);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment