From 068a52b22d34021e2a44acbfa43608a1143cfca2 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Wed, 20 Aug 2014 16:50:46 -0700 Subject: [PATCH 01/28] Utility method to assert valid keys. --- core/lib/compass/util.rb | 7 +++++++ core/test/units/util_test.rb | 31 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 core/test/units/util_test.rb diff --git a/core/lib/compass/util.rb b/core/lib/compass/util.rb index 64455743a5..9ef06b5095 100644 --- a/core/lib/compass/util.rb +++ b/core/lib/compass/util.rb @@ -16,4 +16,11 @@ def blank?(value) end end + def assert_valid_keys(hash, *keys) + invalid_keys = hash.keys - keys + if invalid_keys.any? + raise ArgumentError, "Invalid key#{'s' if invalid_keys.size > 1} found: #{invalid_keys.map{|k| k.inspect}.join(", ")}" + end + end + end diff --git a/core/test/units/util_test.rb b/core/test/units/util_test.rb new file mode 100644 index 0000000000..030ac1a6ae --- /dev/null +++ b/core/test/units/util_test.rb @@ -0,0 +1,31 @@ +#! /usr/bin/env ruby +test_directory = File.expand_path(File.dirname(__FILE__)) +$: << test_directory unless $:.include? test_directory +require 'test_helper' + +class UtilTest < Test::Unit::TestCase + + def test_assert_valid_keys + Compass::Util.assert_valid_keys({:key1 => true}, :key1, :key2, :key3) + begin + Compass::Util.assert_valid_keys({:key1 => true, :invalid => true}, :key1, :key2, :key3) + fail "Did not raise" + rescue ArgumentError => e + assert_equal "Invalid key found: :invalid", e.message + end + begin + Compass::Util.assert_valid_keys({:key1 => true, :invalid => true, :another_invalid => true}, + :key1, :key2, :key3) + fail "Did not raise" + rescue ArgumentError => e + assert_equal "Invalid keys found: :invalid, :another_invalid", e.message + end + end + + private + + def options + @options ||= {} + end +end + From 5fea13d75270d265ddf9ad0ee4c95f42886018ef Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sun, 24 Aug 2014 13:22:32 -0700 Subject: [PATCH 02/28] Add basic asset collection configuration via ruby and use it for image urls. --- .../busted_image_urls/css/screen.css | 2 +- .../stylesheets/compass/css/images.css | 2 +- cli/test/units/configuration_test.rb | 36 +- core/lib/compass/configuration.rb | 5 +- .../compass/configuration/asset_collection.rb | 234 ++++++++++++ core/lib/compass/configuration/data.rb | 29 +- core/lib/compass/core.rb | 2 + core/lib/compass/core/asset_url_resolver.rb | 144 +++++++ core/lib/compass/core/http_util.rb | 41 ++ .../core/sass_extensions/functions/urls.rb | 60 +-- core/lib/compass/util.rb | 7 + .../projects/busted_image_urls/css/screen.css | 2 +- .../projects/compass/css/images.css | 2 +- core/test/units/asset_collection_test.rb | 356 ++++++++++++++++++ .../fancy_fonts/font1.ttf | 0 .../fancy_images/fancy_subdir/image2.png | 0 .../fancy_images/image1.jpg | 0 .../fancy_images/image3.svg | 0 .../more_fonts/morefont.ttf | 0 .../more_images/moreimage.jpg | 0 .../asset_resolver_tests/fonts/default.ttf | 0 .../asset_resolver_tests/images/default.jpg | 0 core/test/units/test_helper.rb | 13 + 23 files changed, 859 insertions(+), 76 deletions(-) create mode 100644 core/lib/compass/configuration/asset_collection.rb create mode 100644 core/lib/compass/core/asset_url_resolver.rb create mode 100644 core/lib/compass/core/http_util.rb create mode 100755 core/test/units/asset_collection_test.rb create mode 100644 core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_fonts/font1.ttf create mode 100644 core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_images/fancy_subdir/image2.png create mode 100644 core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_images/image1.jpg create mode 100644 core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_images/image3.svg create mode 100644 core/test/units/fixtures/asset_resolver_tests/asset_collection_two/more_fonts/morefont.ttf create mode 100644 core/test/units/fixtures/asset_resolver_tests/asset_collection_two/more_images/moreimage.jpg create mode 100644 core/test/units/fixtures/asset_resolver_tests/fonts/default.ttf create mode 100644 core/test/units/fixtures/asset_resolver_tests/images/default.jpg diff --git a/cli/test/fixtures/stylesheets/busted_image_urls/css/screen.css b/cli/test/fixtures/stylesheets/busted_image_urls/css/screen.css index ab36dbc7dd..3baea04937 100644 --- a/cli/test/fixtures/stylesheets/busted_image_urls/css/screen.css +++ b/cli/test/fixtures/stylesheets/busted_image_urls/css/screen.css @@ -1,4 +1,4 @@ -.showgrid { background-image: url('http://assets0.example.com/images/grid-BUSTED.png'); } +.showgrid { background-image: url('http://assets3.example.com/images/grid-BUSTED.png'); } .inlinegrid { background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAUEAYAAACv1qP4AAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAAZ0lEQVRYw+3QwQ2AIBAFUTEUwI3+uzN7gDscsIgxEuO8An52J11X73OudfxMraXkzHfO3Y98nQEhA0IGhAwIGRAyIGRAyICQASEDQgaEDAgZEDIgZEDIgJABoZzSGK3tPuN9ERFP7Nw4fg+c5g8V1wAAAABJRU5ErkJggg=='); } diff --git a/cli/test/fixtures/stylesheets/compass/css/images.css b/cli/test/fixtures/stylesheets/compass/css/images.css index e0c4fdae3f..9d05bfd48a 100644 --- a/cli/test/fixtures/stylesheets/compass/css/images.css +++ b/cli/test/fixtures/stylesheets/compass/css/images.css @@ -5,4 +5,4 @@ background-image: url('/images/4x6.png?busted=true'); } .absolute { - background-image: url(http://example.com/images/4x6.png); } + background-image: url('http://example.com/images/4x6.png'); } diff --git a/cli/test/units/configuration_test.rb b/cli/test/units/configuration_test.rb index 7192b26ed7..37a156f79e 100644 --- a/cli/test/units/configuration_test.rb +++ b/cli/test/units/configuration_test.rb @@ -206,24 +206,30 @@ def test_serialization_warns_with_asset_cache_buster_set end def test_cache_buster_file_not_passed_when_the_file_does_not_exist - config = Compass::Configuration::Data.new("test_cache_buster_file_not_passed_when_the_file_does_not_exist") - the_file = nil - was_called = nil - config.asset_cache_buster do |path, file| - was_called = true - the_file = file - "busted=true" - end + FileUtils.mkdir_p("images") + begin + config = Compass::Configuration::Data.new("test_cache_buster_file_not_passed_when_the_file_does_not_exist") + open("images/asdf.gif", "w") {|f| } + the_file = nil + was_called = nil + config.asset_cache_buster do |path, file| + was_called = true + the_file = file + "busted=true" + end - Compass.add_configuration(config) + Compass.add_configuration(config) - sass = Sass::Engine.new(<<-SCSS, Compass.configuration.to_sass_engine_options.merge(:syntax => :scss)) - .foo { background: image-url("asdf.gif") } - SCSS - sass.render - assert was_called - assert_nil the_file + sass = Sass::Engine.new(<<-SCSS, Compass.configuration.to_sass_engine_options.merge(:syntax => :scss)) + .foo { background: image-url("asdf.gif") } + SCSS + sass.render + assert was_called + assert the_file.closed? + ensure + FileUtils.rm_r("images") + end end def test_cache_buster_file_is_closed diff --git a/core/lib/compass/configuration.rb b/core/lib/compass/configuration.rb index 0f31283b71..4ace707885 100644 --- a/core/lib/compass/configuration.rb +++ b/core/lib/compass/configuration.rb @@ -85,7 +85,8 @@ def remove_configuration_property(name) :sprite_load_path, :required_libraries, :loaded_frameworks, - :framework_path + :framework_path, + :asset_collections ] ARRAY_ATTRIBUTE_OPTIONS = { @@ -170,6 +171,6 @@ def deprojectize(path, project_path = nil) end end -%w(defaults inheritance paths data watch adapters).each do |lib| +%w(defaults inheritance paths data watch adapters asset_collection).each do |lib| require "compass/configuration/#{lib}" end diff --git a/core/lib/compass/configuration/asset_collection.rb b/core/lib/compass/configuration/asset_collection.rb new file mode 100644 index 0000000000..7d3c7de1ba --- /dev/null +++ b/core/lib/compass/configuration/asset_collection.rb @@ -0,0 +1,234 @@ +class Compass::Configuration::AbstractAssetCollection + include Compass::Core::HTTPUtil + + attr_writer :configuration + + def configuration + @configuration || Compass.configuration + end + + def as_filesystem_path(url_path) + if File::SEPARATOR == '/' + url_path + else + relative_path = url_path.gsub(%r{/}, File::SEPARATOR) + end + end + + def includes_image?(relative_path) + # Treat root relative urls (without a protocol) like normal if they start with the images path. + if relative_path.start_with?("#{http_images_path}/") + relative_path = relative_path[(http_images_path.size + 1)..-1] + end + fs_relative_path = as_filesystem_path(relative_path) + absolute_path = File.join(images_path, fs_relative_path) + if File.exists?(absolute_path) + [relative_path, absolute_path] + else + nil + end + end + + def includes_font?(relative_path) + # Treat root relative urls (without a protocol) like normal if they start with the fonts path. + if relative_path.start_with?("#{http_fonts_path}/") + relative_path = relative_path[(http_fonts_path.size + 1)..-1] + end + fs_relative_path = as_filesystem_path(relative_path) + absolute_path = File.join(fonts_path, fs_relative_path) + if File.exists?(absolute_path) + [relative_path, absolute_path] + end + end + + def root_path + Sass::Util.abstract! + end + + def http_path + Sass::Util.abstract! + end + + def sass_path + Sass::Util.abstract! + end + + def images_path + Sass::Util.abstract! + end + + def http_images_path + Sass::Util.abstract! + end + + def fonts_path + Sass::Util.abstract! + end + + def http_fonts_path + Sass::Util.abstract! + end + + def asset_host + Sass::Util.abstract! + end + + def asset_cache_buster + Sass::Util.abstract! + end +end + +class Compass::Configuration::AssetCollection < Compass::Configuration::AbstractAssetCollection + include Compass::Util + + attr_reader :options + + # @param options The paths to the asset collection. + # @option :root_path The absolute path to the asset collection + # @option :root_dir A relative path to the asset collection from the project path. + # @option :http_path Web root location of assets in this collection. + # Starts with '/'. + # @option :http_dir Web root location of assets in this collection. + # Relative to the project's `http_path`. + # @option :sass_dir Sass directory to be added to the Sass import paths. + # Relative to the :root_path or :root_dir. Defaults to `sass`. + # @option :fonts_dir Directory of fonts to be added to the font look up path. + # Relative to the :root_path or :root_dir. Defaults to `fonts`. + # @option :http_fonts_dir Where to find fonts on the webserver relative to + # the http_path or http_dir. Defaults to /. + # Can be overridden by setting :http_fonts_path. + # @option :http_fonts_path Where to find fonts on the webserver. + # @option :images_dir Directory of images to be added to the image look up path. + # Relative to the :root_path or :root_dir. Defaults to `images`. + # @option :http_images_dir Where to find images on the webserver relative to + # the http_path or http_dir. Defaults to /. + # Can be overridden by setting :http_images_path. + # @option :http_images_path Where to find images on the webserver. + # @option :asset_host A string starting with 'http://' for a single host, + # or a lambda or proc that will compute the asset host for assets in this collection. + # If :http_dir is set instead of http_path, this defaults to the project's asset_host. + # @option :asset_cache_buster A string, :none, or + # or a lambda or proc that will compute the cache_buster for assets in this collection. + # If :http_dir is set instead of http_path, this defaults to the project's asset_cache_buster. + def initialize(options, configuration = nil) + symbolize_keys!(options) + assert_valid_keys(options, :root_path, :root_dir, :http_path, :http_dir, :sass_dir, + :fonts_dir, :http_fonts_dir, :http_fonts_path, + :images_dir, :http_images_dir, :http_images_path, + :asset_host, :asset_cache_buster) + unless options.has_key?(:root_path) || options.has_key?(:root_dir) + raise ArgumentError, "Either :root_path or :root_dir must be specified." + end + unless options.has_key?(:http_path) || options.has_key?(:http_dir) + raise ArgumentError, "Either :http_path or :http_dir must be specified." + end + @options = options + @configuration = configuration + end + + def root_path + return @root_path if defined?(@root_path) + @root_path = @options[:root_path] || File.join(configuration.project_path, @options[:root_dir]) + end + + def http_path + return @http_path if defined?(@http_path) + @http_path = @options[:http_path] || url_join(configuration.http_path, @options[:http_dir]) + end + + def sass_path + return @sass_path if defined?(@sass_path) + @sass_path = if options[:sass_dir] + File.join(root_path, options[:sass_dir]) + end + end + + def images_path + return @images_path if defined?(@images_path) + @images_path = if options[:images_dir] + File.join(root_path, options[:images_dir]) + end + end + + def http_images_path + return @http_images_path if defined?(@http_images_path) + @http_images_path = if options[:http_images_path] + options[:http_images_path] + elsif options[:http_images_dir] + url_join(http_path, options[:http_images_dir]) + elsif options[:images_dir] + url_join(http_path, options[:images_dir]) + end + end + + + def fonts_path + return @fonts_path if defined?(@fonts_path) + @fonts_path = if options[:fonts_dir] + File.join(root_path, options[:fonts_dir]) + end + end + + def http_fonts_path + return @http_fonts_path if defined?(@http_fonts_path) + @http_fonts_path = if options[:http_fonts_path] + options[:http_fonts_path] + elsif options[:http_fonts_dir] + url_join(http_path, options[:http_fonts_dir]) + elsif options[:fonts_dir] + url_join(http_path, options[:fonts_dir]) + end + end + + def asset_host + return options[:asset_host] if options.has_key?(:asset_host) + if options[:http_dir] + configuration.asset_host + end + end + + def asset_cache_buster + return options[:asset_cache_buster] if options.has_key?(:asset_cache_buster) + if options[:http_dir] + configuration.asset_cache_buster + end + end +end + +class Compass::Configuration::DefaultAssetCollection < Compass::Configuration::AbstractAssetCollection + def root_path + configuration.project_path + end + + def http_path + configuration.http_path + end + + def sass_path + configuration.sass_path + end + + def images_path + configuration.images_path + end + + def http_images_path + configuration.http_images_path + end + + def fonts_path + configuration.fonts_path + end + + def http_fonts_path + configuration.http_fonts_path + end + + def asset_host + configuration.asset_host + end + + def asset_cache_buster + configuration.asset_cache_buster + end +end diff --git a/core/lib/compass/configuration/data.rb b/core/lib/compass/configuration/data.rb index 54125cb9ee..de94af0b5e 100644 --- a/core/lib/compass/configuration/data.rb +++ b/core/lib/compass/configuration/data.rb @@ -81,7 +81,7 @@ class Data end def initialize(name, attr_hash = nil) - raise "I need a name!" unless name + raise "I need a name!" unless name && (name.is_a?(String) || name.is_a?(Symbol)) @name = name set_all(attr_hash) if attr_hash self.top_level = self @@ -95,6 +95,14 @@ def set_all(attr_hash) end end + alias http_path_without_error= http_path= + def http_path=(path) + if path == :relative + raise ArgumentError, ":relative is no longer a valid value for http_path. Please set relative_assets = true instead." + end + self.http_path_without_error = path + end + def add_import_path(*paths) paths.map!{|p| defined?(Pathname) && Pathname === p ? p.to_s : p} # The @added_import_paths variable works around an issue where @@ -106,6 +114,15 @@ def add_import_path(*paths) end end + + # Add a location where sass, image, and font assets can be found. + # @see AssetCollection#initialize for options + def add_asset_collection(options) + @url_resolver = nil + @asset_collections ||= [] + @asset_collections << AssetCollection.new(options) + end + # When called with a block, defines the asset host url to be used. # The block must return a string that starts with a protocol (E.g. http). # The block will be passed the root-relative url of the asset. @@ -192,7 +209,15 @@ def discover(frameworks_dir) def relative_assets? # the http_images_path is deprecated, but here for backwards compatibility. - relative_assets || http_images_path == :relative + relative_assets + end + + def url_resolver + if top_level == self + @url_resolver = Compass::Core::AssetUrlResolver.new(asset_collections.to_a, self) + else + top_level.url_resolver + end end end end diff --git a/core/lib/compass/core.rb b/core/lib/compass/core.rb index 242c0b6771..f5ad900df0 100644 --- a/core/lib/compass/core.rb +++ b/core/lib/compass/core.rb @@ -65,6 +65,8 @@ def shared_extension_paths require 'compass/util' require "compass/frameworks" require "compass/core/caniuse" +require "compass/core/http_util" +require "compass/core/asset_url_resolver" require 'compass/core/sass_extensions' require 'compass/error' require 'compass/browser_support' diff --git a/core/lib/compass/core/asset_url_resolver.rb b/core/lib/compass/core/asset_url_resolver.rb new file mode 100644 index 0000000000..8224175ce2 --- /dev/null +++ b/core/lib/compass/core/asset_url_resolver.rb @@ -0,0 +1,144 @@ +class Compass::Core::AssetUrlResolver + include Compass::Core::HTTPUtil + + class AssetNotFound < Sass::SyntaxError + def initialize(type, path, asset_collections) + asset_search_paths = asset_collections.map{|ac| ac.send(:"#{type}s_path") } + super("Could not find #{path} in #{ asset_search_paths.join(", ")}") + end + end + + attr_accessor :asset_collections + attr_accessor :configuration + + def initialize(asset_collections, configuration = nil) + @configuration = configuration || Compass.configuration + @asset_collections = asset_collections.dup + unless @asset_collections.find {|ac| Compass::Configuration::DefaultAssetCollection === ac } + @asset_collections.unshift(Compass::Configuration::DefaultAssetCollection.new) + end + if configuration + @asset_collections.each {|ac| ac.configuration = configuration } + end + end + + # Compute a url for a given asset type (:image or :font) + def compute_url(type, relative_path, relative_to_css_url = nil, use_cache_buster = true) + # pass through fully specified urls + return relative_path if relative_path.start_with?("http://") + + # If the image has an target reference, remove it (Common with SVG) + clean_relative_path, target = relative_path.split("#", 2) + + # If the image has a query, remove it + clean_relative_path, query = clean_relative_path.split("?", 2) + + # Get rid of silliness in the url + clean_relative_path = expand_url_path(clean_relative_path) + + # Find the asset collection that includes this asset + asset_collection, clean_relative_path, real_path = find_collection(type, clean_relative_path) + + # Didn't find the asset, but it's a full url so just return it. + return relative_path if asset_collection.nil? && relative_path.start_with?("/") + + # Raise an error for relative paths if we didn't find it on the search path. + raise AssetNotFound.new(type, relative_path, @asset_collections) unless asset_collection + + # Make a root-relative url (starting with /) + asset_url = url_join(asset_collection.send(:"http_#{type}s_path"), clean_relative_path) + + # Compute asset cache buster + busted_path, busted_query = cache_buster(asset_collection, asset_url, real_path) if use_cache_buster + asset_url = busted_path if busted_path + query = [query, busted_query].compact.join("&") if busted_query + + # Convert path to a relative url if a css file is specified. + relative_url = compute_relative_path(relative_to_css_url, asset_url) if relative_to_css_url + + # Compute asset host when not relative and one is provided + asset_host = if asset_collection.asset_host && relative_url.nil? + asset_collection.asset_host.call(asset_url) + end + + # build the full url + url = url_join(asset_host || "", relative_url || asset_url) + url << "?" if query + url << query if query + url << "#" if target + url << target if target + return url + end + + protected + + def find_collection(type, relative_path) + asset_collection = nil + clean_relative_path = nil + absolute_path = nil + @asset_collections.each do |ac| + cp, ap = ac.send(:"includes_#{type}?", relative_path) + if ap + asset_collection = ac + absolute_path = ap + clean_relative_path = cp + break + end + end + [asset_collection, clean_relative_path, absolute_path] + end + + def absolute_path?(path) + path[0..0] == "/" || path[0..3] == "http" + end + + def cache_buster(asset_collection, path, real_path) + cache_buster = compute_cache_buster(asset_collection, path, real_path) + return [path, nil] if cache_buster.nil? + cache_buster = {:query => cache_buster} if cache_buster.is_a?(String) + [cache_buster[:path] || path, cache_buster[:query]] + end + + + def compute_cache_buster(asset_collection, path, real_path) + file = nil + if asset_collection.asset_cache_buster == :none + nil + elsif asset_collection.asset_cache_buster + args = [path] + if asset_collection.asset_cache_buster.arity > 1 + file = File.new(real_path) + args << file + end + asset_collection.asset_cache_buster.call(*args) + else + default_cache_buster(path, real_path) + end + ensure + file.close if file + end + + def default_cache_buster(path, real_path) + if File.readable?(real_path) + File.mtime(real_path).to_i.to_s + else + Compass::Util.compass_warn("WARNING: '#{real_path}' cannot be read.") + nil + end + end + + def compute_relative_path(from_url, to_url) + from_components = expand_url_path(from_url).split("/") + from_components.pop # drop the filename from the source + to_components = expand_url_path(to_url).split("/") + to_base = to_components.pop + while from_components.first == to_components.first + break if from_components.empty? + from_components.shift + to_components.shift + end + + ([".."] * from_components.size + to_components + [to_base]).join("/") + end + +end diff --git a/core/lib/compass/core/http_util.rb b/core/lib/compass/core/http_util.rb new file mode 100644 index 0000000000..216758cb90 --- /dev/null +++ b/core/lib/compass/core/http_util.rb @@ -0,0 +1,41 @@ +module Compass::Core::HTTPUtil + # like File#join, but always uses '/' instead of File::SEPARATOR + def url_join(*args) + args.inject("") do |m, a| + m << "/" unless m.end_with?('/') || a.start_with?('/') if m.length > 0 + m.gsub!(%r{/+$}, '') if a.start_with?('/') + m << a + end + end + + # Eliminates parent directory references (E.g. "..") and + # self directory references references (E.g. ".") from urls. + # Removes any duplicated separators (E.g. //) + # path should not include the protol, host, query param or target. + def expand_url_path(url) + # We remove the leading path otherwise we think there's an extra segment that can be removed + prefix = "/" if url.start_with?("/") + segments = url.gsub(%r{//+}, '/').split("/") + segments.shift if prefix + segments.push("") if url.end_with?("/") + segments.reverse! + result_segments = [] + parent_count = 0 + segments.each do |segment| + if segment == ".." + parent_count += 1 + elsif segment == "." + # skip it + elsif parent_count > 0 + parent_count -= 1 + else + result_segments << segment + end + end + if parent_count > 0 + raise ArgumentError, "Invalid URL: #{url} (not enough parent directories)" + end + result_segments.reverse! + prefix.to_s + result_segments.join("/") + end +end diff --git a/core/lib/compass/core/sass_extensions/functions/urls.rb b/core/lib/compass/core/sass_extensions/functions/urls.rb index 25dcc58252..dd15da4843 100644 --- a/core/lib/compass/core/sass_extensions/functions/urls.rb +++ b/core/lib/compass/core/sass_extensions/functions/urls.rb @@ -102,6 +102,7 @@ def font_url(path, only_path = bool(false), cache_buster = bool(true)) end module ImageUrl + include Compass::Core::HTTPUtil def self.included(base) if base.respond_to?(:declare) base.declare :image_url, [:path] @@ -111,62 +112,15 @@ def self.included(base) end def image_url(path, only_path = bool(false), cache_buster = bool(true)) path = path.value # get to the string value of the literal. - - if path =~ %r{^#{Regexp.escape(Compass.configuration.http_images_path)}/(.*)} - # Treat root relative urls (without a protocol) like normal if they start with - # the images path. - path = $1 - elsif absolute_path?(path) - # Short curcuit if they have provided an absolute url. - return unquoted_string("url(#{path})") - end - - # Compute the path to the image, either root relative or stylesheet relative - # or nil if the http_images_path is not set in the configuration. - http_images_path = if relative? - compute_relative_path(Compass.configuration.images_path) - elsif Compass.configuration.http_images_path - Compass.configuration.http_images_path - else - Compass.configuration.http_root_relative(Compass.configuration.images_dir) - end - - # Compute the real path to the image on the file stystem if the images_dir is set. - real_path = if Compass.configuration.images_path - File.join(Compass.configuration.images_path, path.gsub(/#.*$/,"")) - else - File.join(Compass.configuration.project_path, path.gsub(/#.*$/,"")) - end - - # prepend the path to the image if there's one - if http_images_path - http_images_path = "#{http_images_path}/" unless http_images_path[-1..-1] == "/" - path = "#{http_images_path}#{path}" - end - - # Compute the asset host unless in relative mode. - asset_host = if !relative? && Compass.configuration.asset_host - Compass.configuration.asset_host.call(path) - end - - # Compute and append the cache buster if there is one. - if cache_buster.to_bool - path, anchor = path.split("#", 2) - if cache_buster.is_a?(Sass::Script::Value::String) - path += "#{path["?"] ? "&" : "?"}#{cache_buster.value}" - else - path = cache_busted_path(path, real_path) - end - path = "#{path}#{"#" if anchor}#{anchor}" + css_file = nil + if Compass.configuration.relative_assets? && options[:css_filename] && options[:css_filename].start_with?("#{Compass.configuration.css_path}/") + css_file = url_join(Compass.configuration.http_stylesheets_path, options[:css_filename][(Compass.configuration.css_path.size + 1)..-1]) end - - # prepend the asset host if there is one. - path = "#{asset_host}#{'/' unless path[0..0] == "/"}#{path}" if asset_host - + url = Compass.configuration.url_resolver.compute_url(:image, path, css_file, cache_buster.to_bool) if only_path.to_bool - unquoted_string(clean_path(path)) + unquoted_string(url) else - clean_url(path) + unquoted_string("url('#{url}')") end end end diff --git a/core/lib/compass/util.rb b/core/lib/compass/util.rb index 9ef06b5095..f617334605 100644 --- a/core/lib/compass/util.rb +++ b/core/lib/compass/util.rb @@ -23,4 +23,11 @@ def assert_valid_keys(hash, *keys) end end + def symbolize_keys!(hash) + hash.keys.select {|k| k.is_a?(String)}.each do |k| + hash[k.to_sym] = hash.delete(k) + end + nil + end + end diff --git a/core/test/integrations/projects/busted_image_urls/css/screen.css b/core/test/integrations/projects/busted_image_urls/css/screen.css index 12567c02b3..301144a9b8 100644 --- a/core/test/integrations/projects/busted_image_urls/css/screen.css +++ b/core/test/integrations/projects/busted_image_urls/css/screen.css @@ -1,4 +1,4 @@ -.showgrid { background-image: url('http://assets0.example.com/images/grid-BUSTED.png'); } +.showgrid { background-image: url('http://assets3.example.com/images/grid-BUSTED.png'); } .inlinegrid { background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAUEAYAAACv1qP4AAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAAZ0lEQVRYw+3QwQ2AIBAFUTEUwI3+uzN7gDscsIgxEuO8An52J11X73OudfxMraXkzHfO3Y98nQEhA0IGhAwIGRAyIGRAyICQASEDQgaEDAgZEDIgZEDIgJABoZzSGK3tPuN9ERFP7Nw4fg+c5g8V1wAAAABJRU5ErkJggg=='); } diff --git a/core/test/integrations/projects/compass/css/images.css b/core/test/integrations/projects/compass/css/images.css index e0c4fdae3f..9d05bfd48a 100644 --- a/core/test/integrations/projects/compass/css/images.css +++ b/core/test/integrations/projects/compass/css/images.css @@ -5,4 +5,4 @@ background-image: url('/images/4x6.png?busted=true'); } .absolute { - background-image: url(http://example.com/images/4x6.png); } + background-image: url('http://example.com/images/4x6.png'); } diff --git a/core/test/units/asset_collection_test.rb b/core/test/units/asset_collection_test.rb new file mode 100755 index 0000000000..40b183b092 --- /dev/null +++ b/core/test/units/asset_collection_test.rb @@ -0,0 +1,356 @@ +#! /usr/bin/env ruby +test_directory = File.expand_path(File.dirname(__FILE__)) +$: << test_directory unless $:.include? test_directory +require 'test_helper' + +class AssetCollectionTest < Test::Unit::TestCase + + include Compass::Configuration + include Compass::Core::HTTPUtil + + ABSOLUTE_COLLECTION_OPTS = { + :root_path => "/tmp/some_assets", + :sass_dir => "scss", + :fonts_dir => "fnts", + :images_dir => "imgs", + :http_path => "/some-assets", + :asset_host => nil, + :asset_cache_buster => :none + } + + RELATIVE_COLLECTION_OPTS = { + :root_dir => "some_assets", + :sass_dir => "scss", + :fonts_dir => "fnts", + :images_dir => "imgs", + :http_dir => "some-assets", + :asset_host => nil, + :asset_cache_buster => :none + } + + HTTP_RELATIVE_COLLECTION_OPTS = { + :root_dir => "some_assets", + :sass_dir => "scss", + :fonts_dir => "fnts", + :images_dir => "imgs", + :http_fonts_dir => "hfnts", + :http_images_dir => "himgs", + :http_dir => "some-assets", + :asset_host => nil, + :asset_cache_buster => :none + } + + HTTP_ABSOLUTE_COLLECTION_OPTS = { + :root_dir => "some_assets", + :sass_dir => "scss", + :fonts_dir => "fnts", + :images_dir => "imgs", + :http_fonts_path => "/font-assets", + :http_images_path => "/image-assets", + :http_dir => "some-assets", + :asset_host => nil, + :asset_cache_buster => :none + } + + def test_asset_collection_keys + valid_sets = [ABSOLUTE_COLLECTION_OPTS, RELATIVE_COLLECTION_OPTS, + HTTP_RELATIVE_COLLECTION_OPTS, HTTP_ABSOLUTE_COLLECTION_OPTS] + + valid_sets.each do |v| + AssetCollection.new(v) + end + end + + def test_invalid_collection_keys + assert_raise_message(ArgumentError, "Either :root_path or :root_dir must be specified.") do + AssetCollection.new({}) + end + end + + def test_invalid_collection_keys + assert_raise_message(ArgumentError, "Either :http_path or :http_dir must be specified.") do + AssetCollection.new({:root_path => "/tmp"}) + end + end + + + def test_resolved_attributes_absolute + collection = AssetCollection.new(ABSOLUTE_COLLECTION_OPTS) + assert_equal "/tmp/some_assets", collection.root_path + assert_equal "/some-assets", collection.http_path + assert_equal "/tmp/some_assets/scss", collection.sass_path + assert_equal "/tmp/some_assets/fnts", collection.fonts_path + assert_equal "/tmp/some_assets/imgs", collection.images_path + assert_equal "/some-assets/fnts", collection.http_fonts_path + assert_equal "/some-assets/imgs", collection.http_images_path + assert_equal nil, collection.asset_host + assert_equal :none, collection.asset_cache_buster + end + + def test_resolved_attributes_relative + collection = AssetCollection.new(RELATIVE_COLLECTION_OPTS) + assert_equal "./some_assets", collection.root_path + assert_equal "/some-assets", collection.http_path + assert_equal "./some_assets/scss", collection.sass_path + assert_equal "./some_assets/fnts", collection.fonts_path + assert_equal "./some_assets/imgs", collection.images_path + assert_equal "/some-assets/fnts", collection.http_fonts_path + assert_equal "/some-assets/imgs", collection.http_images_path + assert_equal nil, collection.asset_host + assert_equal :none, collection.asset_cache_buster + end + + def test_resolved_attributes_http_absolute + collection = AssetCollection.new(HTTP_ABSOLUTE_COLLECTION_OPTS) + assert_equal "./some_assets", collection.root_path + assert_equal "/some-assets", collection.http_path + assert_equal "./some_assets/scss", collection.sass_path + assert_equal "./some_assets/fnts", collection.fonts_path + assert_equal "./some_assets/imgs", collection.images_path + assert_equal "/font-assets", collection.http_fonts_path + assert_equal "/image-assets", collection.http_images_path + assert_equal nil, collection.asset_host + assert_equal :none, collection.asset_cache_buster + end + + def test_resolved_attributes_http_relative + collection = AssetCollection.new(HTTP_RELATIVE_COLLECTION_OPTS) + assert_equal "./some_assets", collection.root_path + assert_equal "/some-assets", collection.http_path + assert_equal "./some_assets/scss", collection.sass_path + assert_equal "./some_assets/fnts", collection.fonts_path + assert_equal "./some_assets/imgs", collection.images_path + assert_equal "/some-assets/hfnts", collection.http_fonts_path + assert_equal "/some-assets/himgs", collection.http_images_path + assert_equal nil, collection.asset_host + assert_equal :none, collection.asset_cache_buster + end + + def test_resolved_attributes_absolute_default + asset_host_proc = proc {|url| "http://something.com" } + asset_cache_buster_proc = proc {|url, file| nil } + Compass.configuration.asset_host(&asset_host_proc) + Compass.configuration.asset_cache_buster(&asset_cache_buster_proc) + collection = AssetCollection.new(:root_path => ABSOLUTE_COLLECTION_OPTS[:root_path], + :http_path => ABSOLUTE_COLLECTION_OPTS[:http_path]) + assert_equal "/tmp/some_assets", collection.root_path + assert_equal "/some-assets", collection.http_path + assert_equal nil, collection.sass_path + assert_equal nil, collection.fonts_path + assert_equal nil, collection.images_path + assert_equal nil, collection.asset_host + assert_equal nil, collection.asset_cache_buster + end + + def test_resolved_attributes_relative_default + asset_host_proc = proc {|url| "http://something.com" } + asset_cache_buster_proc = proc {|url, file| nil } + Compass.configuration.asset_host(&asset_host_proc) + Compass.configuration.asset_cache_buster(&asset_cache_buster_proc) + collection = AssetCollection.new(:root_dir => RELATIVE_COLLECTION_OPTS[:root_dir], + :http_dir => RELATIVE_COLLECTION_OPTS[:http_dir]) + assert_equal "./some_assets", collection.root_path + assert_equal "/some-assets", collection.http_path + assert_equal nil, collection.sass_path + assert_equal nil, collection.fonts_path + assert_equal nil, collection.images_path + assert_equal asset_host_proc, collection.asset_host + assert_equal asset_cache_buster_proc, collection.asset_cache_buster + end + + def test_url_join + assert_equal "foo/bar", url_join("foo", "bar") + assert_equal "foo/bar/baz", url_join("foo", "bar", "baz") + assert_equal "foo/bar", url_join("foo/", "bar") + assert_equal "foo/bar/baz", url_join("foo/", "bar/", "baz") + end + + def test_expand_url_path + assert_equal "/", expand_url_path("/") + assert_equal "/foo", expand_url_path("/foo") + assert_equal "/foo/", expand_url_path("/foo/") + assert_equal "/", expand_url_path("/foo/..") + assert_equal "", expand_url_path("foo/..") + assert_equal "d", expand_url_path("a/../b/../c/../d") + assert_equal "d", expand_url_path("a/../b/c/../../d") + assert_equal "a/b", expand_url_path("a//b") + assert_equal "a/b", expand_url_path("a/./b") + assert_raise_message(ArgumentError, "Invalid URL: .. (not enough parent directories)") do + expand_url_path("..") + end + assert_raise_message(ArgumentError, "Invalid URL: a/../b/c/../../../d (not enough parent directories)") do + expand_url_path("a/../b/c/../../../d") + end + end + + def test_asset_url_resolver + fixtures_dir = File.expand_path("fixtures/asset_resolver_tests", File.dirname(__FILE__)) + configuration = Compass::Configuration::Data.new("test", :project_path => fixtures_dir, :asset_cache_buster => :none) + configuration.extend(Compass::Configuration::Defaults) + collection1 = Compass::Configuration::AssetCollection.new( + {:root_dir => "asset_collection_one", + :http_dir => "asset-collection-one", + :fonts_dir => "fancy_fonts", + :images_dir => "fancy_images", + :asset_cache_buster => :none} + ) + collection2 = Compass::Configuration::AssetCollection.new( + {:root_dir => "asset_collection_two", + :http_dir => "asset-collection-two", + :fonts_dir => "more_fonts", + :images_dir => "more_images", + :asset_cache_buster => :none} + ) + resolver = Compass::Core::AssetUrlResolver.new([collection1, collection2], configuration) + assert_equal "/asset-collection-two/more_images/moreimage.jpg", + resolver.compute_url(:image, "moreimage.jpg") + assert_equal "/asset-collection-one/fancy_images/image1.jpg", + resolver.compute_url(:image, "image1.jpg") + assert_equal "/images/default.jpg", + resolver.compute_url(:image, "default.jpg") + assert_equal "/asset-collection-two/more_fonts/morefont.ttf", + resolver.compute_url(:font, "morefont.ttf") + assert_equal "/asset-collection-one/fancy_fonts/font1.ttf", + resolver.compute_url(:font, "font1.ttf") + assert_equal "/fonts/default.ttf", + resolver.compute_url(:font, "default.ttf") + assert_equal "/asset-collection-one/fancy_images/fancy_subdir/image2.png", + resolver.compute_url(:image, "fancy_subdir/image2.png") + assert_equal "/asset-collection-one/fancy_images/image1.jpg", + resolver.compute_url(:image, "fancy_subdir/../image1.jpg") + assert_equal "/asset-collection-one/fancy_images/image3.svg#something", + resolver.compute_url(:image, "image3.svg#something") + assert_equal "/asset-collection-one/fancy_images/image3.svg?q=1234&s=4321#something", + resolver.compute_url(:image, "image3.svg?q=1234&s=4321#something") + assert_equal "/does-not-exist/thing.jpg", + resolver.compute_url(:image, "/does-not-exist/thing.jpg") + assert_equal "http://google.com/logo.png", + resolver.compute_url(:image, "http://google.com/logo.png") + error_message = "Could not find doesnotexist.jpg in " + + "#{resolver.asset_collections.map{|ac| ac.images_path}.join(", ")}" + assert_raise_message(Compass::Core::AssetUrlResolver::AssetNotFound, error_message) do + resolver.compute_url(:image, "doesnotexist.jpg") + end + end + + def test_asset_url_resolver_with_asset_hosts_and_busters + fixtures_dir = File.expand_path("fixtures/asset_resolver_tests", File.dirname(__FILE__)) + configuration = Compass::Configuration::Data.new("test", :project_path => fixtures_dir) + configuration.extend(Compass::Configuration::Defaults) + configuration.asset_host do |url| + "http://default-server.org/" + end + configuration.asset_cache_buster do |url, file| + "md5somthing" + end + collection1 = Compass::Configuration::AssetCollection.new( + {:root_dir => "asset_collection_one", + :http_dir => "asset-collection-one", + :fonts_dir => "fancy_fonts", + :images_dir => "fancy_images"} + ) + collection2 = Compass::Configuration::AssetCollection.new( + {:root_dir => "asset_collection_two", + :http_dir => "asset-collection-two", + :fonts_dir => "more_fonts", + :images_dir => "more_images", + :asset_host => proc {|url| "http://more-assets-server.com/" }, + :asset_cache_buster => method(:simple_path_buster)} + ) + resolver = Compass::Core::AssetUrlResolver.new([collection1, collection2], configuration) + assert_equal "http://more-assets-server.com/asset-collection-two/more_images/moreimage-md5something.jpg", + resolver.compute_url(:image, "moreimage.jpg") + assert_equal "http://default-server.org/asset-collection-one/fancy_images/image1.jpg?md5somthing", + resolver.compute_url(:image, "image1.jpg") + assert_equal "http://default-server.org/images/default.jpg?md5somthing", + resolver.compute_url(:image, "default.jpg") + assert_equal "http://more-assets-server.com/asset-collection-two/more_fonts/morefont-md5something.ttf", + resolver.compute_url(:font, "morefont.ttf") + assert_equal "http://default-server.org/asset-collection-one/fancy_fonts/font1.ttf?md5somthing", + resolver.compute_url(:font, "font1.ttf") + assert_equal "http://default-server.org/fonts/default.ttf?md5somthing", + resolver.compute_url(:font, "default.ttf") + assert_equal "http://default-server.org/asset-collection-one/fancy_images/fancy_subdir/image2.png?md5somthing", + resolver.compute_url(:image, "fancy_subdir/image2.png") + assert_equal "http://default-server.org/asset-collection-one/fancy_images/image1.jpg?md5somthing", + resolver.compute_url(:image, "fancy_subdir/../image1.jpg") + assert_equal "http://default-server.org/asset-collection-one/fancy_images/image3.svg?md5somthing#something", + resolver.compute_url(:image, "image3.svg#something") + assert_equal "http://default-server.org/asset-collection-one/fancy_images/image3.svg?q=1234&s=4321&md5somthing#something", + resolver.compute_url(:image, "image3.svg?q=1234&s=4321#something") + assert_equal "/does-not-exist/thing.jpg", + resolver.compute_url(:image, "/does-not-exist/thing.jpg") + assert_equal "http://google.com/logo.png", + resolver.compute_url(:image, "http://google.com/logo.png") + error_message = "Could not find doesnotexist.jpg in " + + "#{resolver.asset_collections.map{|ac| ac.images_path}.join(", ")}" + assert_raise_message(Compass::Core::AssetUrlResolver::AssetNotFound, error_message) do + resolver.compute_url(:image, "doesnotexist.jpg") + end + end + + def test_asset_url_resolver_with_asset_hosts_and_busters_when_relative + fixtures_dir = File.expand_path("fixtures/asset_resolver_tests", File.dirname(__FILE__)) + configuration = Compass::Configuration::Data.new("test", :project_path => fixtures_dir) + configuration.extend(Compass::Configuration::Defaults) + configuration.asset_host do |url| + "http://default-server.org/" + end + configuration.asset_cache_buster do |url, file| + "md5somthing" + end + configuration.relative_assets = true + collection1 = Compass::Configuration::AssetCollection.new( + {:root_dir => "asset_collection_one", + :http_dir => "asset-collection-one", + :fonts_dir => "fancy_fonts", + :images_dir => "fancy_images"} + ) + collection2 = Compass::Configuration::AssetCollection.new( + {:root_dir => "asset_collection_two", + :http_dir => "asset-collection-two", + :fonts_dir => "more_fonts", + :images_dir => "more_images", + :asset_host => proc {|url| "http://more-assets-server.com/" }, + :asset_cache_buster => method(:simple_path_buster)} + ) + resolver = Compass::Core::AssetUrlResolver.new([collection1, collection2], configuration) + assert_equal "../asset-collection-two/more_images/moreimage-md5something.jpg", + resolver.compute_url(:image, "moreimage.jpg", "/css/some-css-file.css") + assert_equal "../asset-collection-one/fancy_images/image1.jpg?md5somthing", + resolver.compute_url(:image, "image1.jpg", "/css/some-css-file.css") + assert_equal "../images/default.jpg?md5somthing", + resolver.compute_url(:image, "default.jpg", "/css/some-css-file.css") + assert_equal "../asset-collection-two/more_fonts/morefont-md5something.ttf", + resolver.compute_url(:font, "morefont.ttf", "/css/some-css-file.css") + assert_equal "../asset-collection-one/fancy_fonts/font1.ttf?md5somthing", + resolver.compute_url(:font, "font1.ttf", "/css/some-css-file.css") + assert_equal "../fonts/default.ttf?md5somthing", + resolver.compute_url(:font, "default.ttf", "/css/some-css-file.css") + assert_equal "../asset-collection-one/fancy_images/fancy_subdir/image2.png?md5somthing", + resolver.compute_url(:image, "fancy_subdir/image2.png", "/css/some-css-file.css") + assert_equal "../asset-collection-one/fancy_images/image1.jpg?md5somthing", + resolver.compute_url(:image, "fancy_subdir/../image1.jpg", "/css/some-css-file.css") + assert_equal "../asset-collection-one/fancy_images/image3.svg?md5somthing#something", + resolver.compute_url(:image, "image3.svg#something", "/css/some-css-file.css") + assert_equal "../asset-collection-one/fancy_images/image3.svg?q=1234&s=4321&md5somthing#something", + resolver.compute_url(:image, "image3.svg?q=1234&s=4321#something", "/css/some-css-file.css") + assert_equal "/does-not-exist/thing.jpg", + resolver.compute_url(:image, "/does-not-exist/thing.jpg", "/css/some-css-file.css") + assert_equal "http://google.com/logo.png", + resolver.compute_url(:image, "http://google.com/logo.png", "/css/some-css-file.css") + error_message = "Could not find doesnotexist.jpg in " + + "#{resolver.asset_collections.map{|ac| ac.images_path}.join(", ")}" + assert_raise_message(Compass::Core::AssetUrlResolver::AssetNotFound, error_message) do + resolver.compute_url(:image, "doesnotexist.jpg") + end + end + + def simple_path_buster(url_path, file) + segments = url_path.split('/') + base = segments.pop + base, ext = base.split(".") + {:path => segments.join("/") + "/" + base + "-md5something" + "." + ext } + end + +end diff --git a/core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_fonts/font1.ttf b/core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_fonts/font1.ttf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_images/fancy_subdir/image2.png b/core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_images/fancy_subdir/image2.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_images/image1.jpg b/core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_images/image1.jpg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_images/image3.svg b/core/test/units/fixtures/asset_resolver_tests/asset_collection_one/fancy_images/image3.svg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/units/fixtures/asset_resolver_tests/asset_collection_two/more_fonts/morefont.ttf b/core/test/units/fixtures/asset_resolver_tests/asset_collection_two/more_fonts/morefont.ttf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/units/fixtures/asset_resolver_tests/asset_collection_two/more_images/moreimage.jpg b/core/test/units/fixtures/asset_resolver_tests/asset_collection_two/more_images/moreimage.jpg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/units/fixtures/asset_resolver_tests/fonts/default.ttf b/core/test/units/fixtures/asset_resolver_tests/fonts/default.ttf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/units/fixtures/asset_resolver_tests/images/default.jpg b/core/test/units/fixtures/asset_resolver_tests/images/default.jpg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/units/test_helper.rb b/core/test/units/test_helper.rb index 2aa0865489..2e4d9dd6d5 100644 --- a/core/test/units/test_helper.rb +++ b/core/test/units/test_helper.rb @@ -1,3 +1,5 @@ +lib_directory = File.expand_path("../../lib", File.dirname(__FILE__)) +$: << lib_directory unless $:.include? lib_directory require 'fileutils' require 'compass/core' @@ -6,3 +8,14 @@ include Compass::Diff +class Test::Unit::TestCase + def assert_raise_message(klass, message) + begin + yield + fail "Exception not raised." + rescue klass => e + assert_equal message, e.message + end + end +end + From d3ad03b737aa28b31e4c018fdca5967f7bf46da0 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sun, 24 Aug 2014 13:46:24 -0700 Subject: [PATCH 03/28] Use asset collections and asset resolver for fonts. --- .../busted_font_urls/css/screen.css | 4 +- .../stylesheets/compass/fonts/font1.eot | 0 .../stylesheets/compass/fonts/font1.woff | 0 cli/test/units/sass_extensions_test.rb | 16 ++-- .../core/sass_extensions/functions/urls.rb | 77 ++++--------------- .../projects/busted_font_urls/css/screen.css | 4 +- .../projects/compass/fonts/font1.eot | 0 .../projects/compass/fonts/font1.woff | 0 8 files changed, 28 insertions(+), 73 deletions(-) create mode 100644 cli/test/fixtures/stylesheets/compass/fonts/font1.eot create mode 100644 cli/test/fixtures/stylesheets/compass/fonts/font1.woff create mode 100644 core/test/integrations/projects/compass/fonts/font1.eot create mode 100644 core/test/integrations/projects/compass/fonts/font1.woff diff --git a/cli/test/fixtures/stylesheets/busted_font_urls/css/screen.css b/cli/test/fixtures/stylesheets/busted_font_urls/css/screen.css index fe08b96758..303caf1a89 100644 --- a/cli/test/fixtures/stylesheets/busted_font_urls/css/screen.css +++ b/cli/test/fixtures/stylesheets/busted_font_urls/css/screen.css @@ -1,8 +1,8 @@ -.showgrid { font-family: url('http://assets3.example.com/fonts/grid-BUSTED.ttf'); } +.showgrid { font-family: url('http://assets2.example.com/fonts/grid-BUSTED.ttf'); } .no-buster { font-family: url('http://assets3.example.com/fonts/grid.ttf'); } -.buster-by-default { font-family: url('http://assets3.example.com/fonts/grid-BUSTED.ttf'); } +.buster-by-default { font-family: url('http://assets2.example.com/fonts/grid-BUSTED.ttf'); } .feed { font-family: url('http://assets3.example.com/fonts/feed.ttf?query_string'); } diff --git a/cli/test/fixtures/stylesheets/compass/fonts/font1.eot b/cli/test/fixtures/stylesheets/compass/fonts/font1.eot new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cli/test/fixtures/stylesheets/compass/fonts/font1.woff b/cli/test/fixtures/stylesheets/compass/fonts/font1.woff new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cli/test/units/sass_extensions_test.rb b/cli/test/units/sass_extensions_test.rb index e6ae94ae8c..cba1a7a00b 100644 --- a/cli/test/units/sass_extensions_test.rb +++ b/cli/test/units/sass_extensions_test.rb @@ -136,18 +136,18 @@ def test_css2_fallback def test_font_files assert_equal '', evaluate('font_files()') - assert_equal "url(/font/name.woff) format('woff'), url(/font/name.woff2) format('woff2'), url(/fonts/name.ttf) format('truetype'), url(/fonts/name.svg#fontpath) format('svg')", evaluate("font-files('/font/name.woff', woff, '/font/name.woff2', woff2, '/fonts/name.ttf', truetype, '/fonts/name.svg#fontpath', svg)") + assert_equal "url('/font/name.woff') format('woff'), url('/font/name.woff2') format('woff2'), url('/fonts/name.ttf') format('truetype'), url('/fonts/name.svg#fontpath') format('svg')", evaluate("font-files('/font/name.woff', woff, '/font/name.woff2', woff2, '/fonts/name.ttf', truetype, '/fonts/name.svg#fontpath', svg)") - assert_equal "url(/font/with/right_ext.woff) format('woff')", evaluate("font_files('/font/with/right_ext.woff')") - assert_equal "url(/font/with/wrong_ext.woff) format('svg')", evaluate("font_files('/font/with/wrong_ext.woff', 'svg')") - assert_equal "url(/font/with/no_ext) format('opentype')", evaluate("font_files('/font/with/no_ext', 'otf')") - assert_equal "url(/font/with/weird.ext) format('truetype')", evaluate("font_files('/font/with/weird.ext', 'ttf')") + assert_equal "url('/font/with/right_ext.woff') format('woff')", evaluate("font_files('/font/with/right_ext.woff')") + assert_equal "url('/font/with/wrong_ext.woff') format('svg')", evaluate("font_files('/font/with/wrong_ext.woff', 'svg')") + assert_equal "url('/font/with/no_ext') format('opentype')", evaluate("font_files('/font/with/no_ext', 'otf')") + assert_equal "url('/font/with/weird.ext') format('truetype')", evaluate("font_files('/font/with/weird.ext', 'ttf')") # unquoted path strings used to break because of a regex test - assert_equal "url(/font/with/right_ext.woff) format('woff')", evaluate("font_files(unquote('/font/with/right_ext.woff'))") + assert_equal "url('/font/with/right_ext.woff') format('woff')", evaluate("font_files(unquote('/font/with/right_ext.woff'))") - assert_equal "url(/font/with/right_ext.woff) format('woff'), url(/font/with/right_ext_also.otf) format('opentype')", evaluate("font_files('/font/with/right_ext.woff', '/font/with/right_ext_also.otf')") - assert_equal "url(/font/with/wrong_ext.woff) format('truetype'), url(/font/with/right_ext.otf) format('opentype')", evaluate("font_files('/font/with/wrong_ext.woff', 'ttf', '/font/with/right_ext.otf')") + assert_equal "url('/font/with/right_ext.woff') format('woff'), url('/font/with/right_ext_also.otf') format('opentype')", evaluate("font_files('/font/with/right_ext.woff', '/font/with/right_ext_also.otf')") + assert_equal "url('/font/with/wrong_ext.woff') format('truetype'), url('/font/with/right_ext.otf') format('opentype')", evaluate("font_files('/font/with/wrong_ext.woff', 'ttf', '/font/with/right_ext.otf')") assert_nothing_raised Sass::SyntaxError do evaluate("font-files('/font/name.woff')") diff --git a/core/lib/compass/core/sass_extensions/functions/urls.rb b/core/lib/compass/core/sass_extensions/functions/urls.rb index dd15da4843..56ebb7e057 100644 --- a/core/lib/compass/core/sass_extensions/functions/urls.rb +++ b/core/lib/compass/core/sass_extensions/functions/urls.rb @@ -48,56 +48,7 @@ def self.included(base) end end def font_url(path, only_path = bool(false), cache_buster = bool(true)) - path = path.value # get to the string value of the literal. - - # Short curcuit if they have provided an absolute url. - if absolute_path?(path) - return unquoted_string("url(#{path})") - end - - # Compute the path to the font file, either root relative or stylesheet relative - # or nil if the http_fonts_path cannot be determined from the configuration. - http_fonts_path = if relative? - compute_relative_path(Compass.configuration.fonts_path) - else - Compass.configuration.http_fonts_path - end - - # Compute the real path to the font on the file system if the fonts_dir is set. - real_path = if Compass.configuration.fonts_dir - File.join(Compass.configuration.fonts_path, path.gsub(/[?#].*$/,"")) - end - - # prepend the path to the font if there's one - if http_fonts_path - http_fonts_path = "#{http_fonts_path}/" unless http_fonts_path[-1..-1] == "/" - path = "#{http_fonts_path}#{path}" - end - - # Compute the asset host unless in relative mode. - asset_host = if !relative? && Compass.configuration.asset_host - Compass.configuration.asset_host.call(path) - end - - # Compute and append the cache buster if there is one. - if cache_buster.to_bool - path, anchor = path.split("#", 2) - if cache_buster.is_a?(Sass::Script::Value::String) - path += "#{path["?"] ? "&" : "?"}#{cache_buster.value}" - else - path = cache_busted_path(path, real_path) - end - path = "#{path}#{"#" if anchor}#{anchor}" - end - - # prepend the asset host if there is one. - path = "#{asset_host}#{'/' unless path[0..0] == "/"}#{path}" if asset_host - - if only_path.to_bool - unquoted_string(clean_path(path)) - else - clean_url(path) - end + resolve_asset_url(:font, path, only_path, cache_buster) end end @@ -111,17 +62,7 @@ def self.included(base) end end def image_url(path, only_path = bool(false), cache_buster = bool(true)) - path = path.value # get to the string value of the literal. - css_file = nil - if Compass.configuration.relative_assets? && options[:css_filename] && options[:css_filename].start_with?("#{Compass.configuration.css_path}/") - css_file = url_join(Compass.configuration.http_stylesheets_path, options[:css_filename][(Compass.configuration.css_path.size + 1)..-1]) - end - url = Compass.configuration.url_resolver.compute_url(:image, path, css_file, cache_buster.to_bool) - if only_path.to_bool - unquoted_string(url) - else - unquoted_string("url('#{url}')") - end + resolve_asset_url(:image, path, only_path, cache_buster) end end @@ -192,6 +133,20 @@ def generated_image_url(path, cache_buster = bool(false)) private + def resolve_asset_url(type, path, only_path, cache_buster) + path = path.value # get to the string value of the literal. + css_file = nil + if Compass.configuration.relative_assets? && options[:css_filename] && options[:css_filename].start_with?("#{Compass.configuration.css_path}/") + css_file = url_join(Compass.configuration.http_stylesheets_path, options[:css_filename][(Compass.configuration.css_path.size + 1)..-1]) + end + url = Compass.configuration.url_resolver.compute_url(type, path, css_file, cache_buster.to_bool) + if only_path.to_bool + unquoted_string(url) + else + unquoted_string("url('#{url}')") + end + end + # Emits a path, taking off any leading "./" def clean_path(url) url = url.to_s diff --git a/core/test/integrations/projects/busted_font_urls/css/screen.css b/core/test/integrations/projects/busted_font_urls/css/screen.css index fe08b96758..303caf1a89 100644 --- a/core/test/integrations/projects/busted_font_urls/css/screen.css +++ b/core/test/integrations/projects/busted_font_urls/css/screen.css @@ -1,8 +1,8 @@ -.showgrid { font-family: url('http://assets3.example.com/fonts/grid-BUSTED.ttf'); } +.showgrid { font-family: url('http://assets2.example.com/fonts/grid-BUSTED.ttf'); } .no-buster { font-family: url('http://assets3.example.com/fonts/grid.ttf'); } -.buster-by-default { font-family: url('http://assets3.example.com/fonts/grid-BUSTED.ttf'); } +.buster-by-default { font-family: url('http://assets2.example.com/fonts/grid-BUSTED.ttf'); } .feed { font-family: url('http://assets3.example.com/fonts/feed.ttf?query_string'); } diff --git a/core/test/integrations/projects/compass/fonts/font1.eot b/core/test/integrations/projects/compass/fonts/font1.eot new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/integrations/projects/compass/fonts/font1.woff b/core/test/integrations/projects/compass/fonts/font1.woff new file mode 100644 index 0000000000..e69de29bb2 From d39aa5630e76c2a1a65145f11334bef30620b311 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sun, 24 Aug 2014 15:10:33 -0700 Subject: [PATCH 04/28] Use the asset resolver for generated images. --- .../compass/configuration/asset_collection.rb | 26 +++++++++ .../core/sass_extensions/functions/urls.rb | 55 +------------------ 2 files changed, 27 insertions(+), 54 deletions(-) diff --git a/core/lib/compass/configuration/asset_collection.rb b/core/lib/compass/configuration/asset_collection.rb index 7d3c7de1ba..714eb93057 100644 --- a/core/lib/compass/configuration/asset_collection.rb +++ b/core/lib/compass/configuration/asset_collection.rb @@ -41,6 +41,10 @@ def includes_font?(relative_path) end end + def includes_generated_image?(relative_path) + nil + end + def root_path Sass::Util.abstract! end @@ -196,6 +200,20 @@ def asset_cache_buster end class Compass::Configuration::DefaultAssetCollection < Compass::Configuration::AbstractAssetCollection + def includes_generated_image?(relative_path) + # Treat root relative urls (without a protocol) like normal if they start with the images path. + if relative_path.start_with?("#{http_generated_images_path}/") + relative_path = relative_path[(http_generated_images_path.size + 1)..-1] + end + fs_relative_path = as_filesystem_path(relative_path) + absolute_path = File.join(generated_images_path, fs_relative_path) + if File.exists?(absolute_path) + [relative_path, absolute_path] + else + nil + end + end + def root_path configuration.project_path end @@ -216,6 +234,14 @@ def http_images_path configuration.http_images_path end + def generated_images_path + configuration.generated_images_path + end + + def http_generated_images_path + configuration.http_generated_images_path + end + def fonts_path configuration.fonts_path end diff --git a/core/lib/compass/core/sass_extensions/functions/urls.rb b/core/lib/compass/core/sass_extensions/functions/urls.rb index 56ebb7e057..90e2dd7ed1 100644 --- a/core/lib/compass/core/sass_extensions/functions/urls.rb +++ b/core/lib/compass/core/sass_extensions/functions/urls.rb @@ -74,60 +74,7 @@ def self.included(base) end end def generated_image_url(path, cache_buster = bool(false)) - path = path.value # get to the string value of the literal. - - if path =~ %r{^#{Regexp.escape(Compass.configuration.http_generated_images_path)}/(.*)} - # Treat root relative urls (without a protocol) like normal if they start with - # the generated_images path. - path = $1 - elsif absolute_path?(path) - # Short curcuit if they have provided an absolute url. - return unquoted_string("url(#{path})") - end - - # Compute the path to the image, either root relative or stylesheet relative - # or nil if the http_generated_images_path is not set in the configuration. - http_generated_images_path = if relative? - compute_relative_path(Compass.configuration.generated_images_path) - elsif Compass.configuration.http_generated_images_path - Compass.configuration.http_generated_images_path - else - Compass.configuration.http_root_relative(Compass.configuration.generated_images_dir) - end - - # Compute the real path to the image on the file stystem if the generated_images_dir is set. - real_path = if Compass.configuration.generated_images_path - File.join(Compass.configuration.generated_images_path, path.gsub(/#.*$/,"")) - else - File.join(Compass.configuration.project_path, path.gsub(/#.*$/,"")) - end - - # prepend the path to the image if there's one - if http_generated_images_path - http_generated_images_path = "#{http_generated_images_path}/" unless http_generated_images_path[-1..-1] == "/" - path = "#{http_generated_images_path}#{path}" - end - - # Compute the asset host unless in relative mode. - asset_host = if !relative? && Compass.configuration.asset_host - Compass.configuration.asset_host.call(path) - end - - # Compute and append the cache buster if there is one. - if cache_buster.to_bool - path, anchor = path.split("#", 2) - if cache_buster.is_a?(Sass::Script::Value::String) - path += "#{path["?"] ? "&" : "?"}#{cache_buster.value}" - else - path = cache_busted_path(path, real_path) - end - path = "#{path}#{"#" if anchor}#{anchor}" - end - - # prepend the asset host if there is one. - path = "#{asset_host}#{'/' unless path[0..0] == "/"}#{path}" if asset_host - - clean_url(path) + resolve_asset_url(:generated_image, path, bool(false), cache_buster) end end From 821db8acf85db75e2bc39474a8fae899efa57710 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sun, 24 Aug 2014 15:37:32 -0700 Subject: [PATCH 05/28] Refactor stylesheet_url with better tools and remove useless code. --- core/lib/compass/core/asset_url_resolver.rb | 14 --- core/lib/compass/core/http_util.rb | 16 +++ .../core/sass_extensions/functions/urls.rb | 100 +++--------------- core/test/units/urls_test.rb | 23 ---- 4 files changed, 28 insertions(+), 125 deletions(-) delete mode 100644 core/test/units/urls_test.rb diff --git a/core/lib/compass/core/asset_url_resolver.rb b/core/lib/compass/core/asset_url_resolver.rb index 8224175ce2..fd9a73bdf9 100644 --- a/core/lib/compass/core/asset_url_resolver.rb +++ b/core/lib/compass/core/asset_url_resolver.rb @@ -127,18 +127,4 @@ def default_cache_buster(path, real_path) end end - def compute_relative_path(from_url, to_url) - from_components = expand_url_path(from_url).split("/") - from_components.pop # drop the filename from the source - to_components = expand_url_path(to_url).split("/") - to_base = to_components.pop - while from_components.first == to_components.first - break if from_components.empty? - from_components.shift - to_components.shift - end - - ([".."] * from_components.size + to_components + [to_base]).join("/") - end - end diff --git a/core/lib/compass/core/http_util.rb b/core/lib/compass/core/http_util.rb index 216758cb90..3ea14f5fd3 100644 --- a/core/lib/compass/core/http_util.rb +++ b/core/lib/compass/core/http_util.rb @@ -38,4 +38,20 @@ def expand_url_path(url) result_segments.reverse! prefix.to_s + result_segments.join("/") end + + # Compute a relative path from one url to another + # the urls should be only the path component (no host, query, or target) + def compute_relative_path(from_url, to_url) + from_components = expand_url_path(from_url).split("/") + from_components.pop # drop the filename from the source + to_components = expand_url_path(to_url).split("/") + to_base = to_components.pop + while from_components.first == to_components.first + break if from_components.empty? + from_components.shift + to_components.shift + end + + ([".."] * from_components.size + to_components + [to_base]).join("/") + end end diff --git a/core/lib/compass/core/sass_extensions/functions/urls.rb b/core/lib/compass/core/sass_extensions/functions/urls.rb index 90e2dd7ed1..0533098ce9 100644 --- a/core/lib/compass/core/sass_extensions/functions/urls.rb +++ b/core/lib/compass/core/sass_extensions/functions/urls.rb @@ -20,21 +20,15 @@ def self.included(base) end end def stylesheet_url(path, only_path = bool(false)) - # Compute the path to the stylesheet, either root relative or stylesheet relative - # or nil if the http_images_path is not set in the configuration. - http_stylesheets_path = if relative? - compute_relative_path(Compass.configuration.css_path) - elsif Compass.configuration.http_stylesheets_path - Compass.configuration.http_stylesheets_path - else - Compass.configuration.http_root_relative(Compass.configuration.css_dir) + url = url_join(Compass.configuration.http_stylesheets_path, path.value) + if Compass.configuration.relative_assets? + url = compute_relative_path(current_css_url_path, url) end - path = "#{http_stylesheets_path}/#{path.value}" if only_path.to_bool - unquoted_string(clean_path(path)) + unquoted_string(expand_url_path(url)) else - clean_url(path) + unquoted_string("url('#{expand_url_path(url)}')") end end end @@ -80,12 +74,15 @@ def generated_image_url(path, cache_buster = bool(false)) private + def current_css_url_path + if options[:css_filename] && options[:css_filename].start_with?("#{Compass.configuration.css_path}/") + url_join(Compass.configuration.http_stylesheets_path, options[:css_filename][(Compass.configuration.css_path.size + 1)..-1]) + end + end + def resolve_asset_url(type, path, only_path, cache_buster) path = path.value # get to the string value of the literal. - css_file = nil - if Compass.configuration.relative_assets? && options[:css_filename] && options[:css_filename].start_with?("#{Compass.configuration.css_path}/") - css_file = url_join(Compass.configuration.http_stylesheets_path, options[:css_filename][(Compass.configuration.css_path.size + 1)..-1]) - end + css_file = current_css_url_path if Compass.configuration.relative_assets? url = Compass.configuration.url_resolver.compute_url(type, path, css_file, cache_buster.to_bool) if only_path.to_bool unquoted_string(url) @@ -93,77 +90,4 @@ def resolve_asset_url(type, path, only_path, cache_buster) unquoted_string("url('#{url}')") end end - - # Emits a path, taking off any leading "./" - def clean_path(url) - url = url.to_s - url = url[0..1] == "./" ? url[2..-1] : url - end - - # Emits a url, taking off any leading "./" - def clean_url(url) - unquoted_string("url('#{clean_path(url)}')") - end - - def relative? - Compass.configuration.relative_assets? - end - - def absolute_path?(path) - path[0..0] == "/" || path[0..3] == "http" - end - - def compute_relative_path(path) - if (target_css_file = options[:css_filename]) - target_path = Pathname.new(File.expand_path(path)) - source_path = Pathname.new(File.dirname(File.expand_path(target_css_file))) - target_path.relative_path_from(source_path).to_s - end - end - - def cache_busted_path(path, real_path) - cache_buster = compute_cache_buster(path, real_path) - if cache_buster.nil? - return path - elsif cache_buster.is_a?(String) - cache_buster = {:query => cache_buster} - else - path = cache_buster[:path] if cache_buster[:path] - end - - if cache_buster[:query] - "#{path}#{path["?"] ? "&" : "?"}#{cache_buster[:query]}" - else - path - end - end - - def compute_cache_buster(path, real_path) - file = nil - if Compass.configuration.asset_cache_buster - args = [path] - if Compass.configuration.asset_cache_buster.arity > 1 - begin - file = File.new(real_path) if real_path - rescue Errno::ENOENT - # pass - end - args << file - end - Compass.configuration.asset_cache_buster.call(*args) - elsif real_path - default_cache_buster(path, real_path) - end - ensure - file.close if file - end - - def default_cache_buster(path, real_path) - if File.readable?(real_path) - File.mtime(real_path).to_i.to_s - else - $stderr.puts "WARNING: '#{File.basename(path)}' was not found (or cannot be read) in #{File.dirname(real_path)}" - end - end - end diff --git a/core/test/units/urls_test.rb b/core/test/units/urls_test.rb deleted file mode 100644 index 4e3d92f3fb..0000000000 --- a/core/test/units/urls_test.rb +++ /dev/null @@ -1,23 +0,0 @@ -#! /usr/bin/env ruby -test_directory = File.expand_path(File.dirname(__FILE__)) -$: << test_directory unless $:.include? test_directory -require 'test_helper' - -class UrlsTest < Test::Unit::TestCase - include Compass::Core::SassExtensions::Functions::Urls - - def test_compute_relative_path - options[:css_filename] = File.expand_path("./test.css") - assert_equal ".", compute_relative_path(".") - assert_equal ".", compute_relative_path(File.expand_path(".")) - options[:css_filename] = "./test.css" - assert_equal ".", compute_relative_path(".") - assert_equal ".", compute_relative_path(File.expand_path(".")) - end - - private - - def options - @options ||= {} - end -end From 9ecba96aa93ddb30ab510baccb8b8d6d7b40a861 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Mon, 25 Aug 2014 12:27:12 -0700 Subject: [PATCH 06/28] Allow sass-based configuration of asset collections. --- core/lib/compass/configuration.rb | 1 + .../compass/configuration/asset_collection.rb | 2 +- .../functions/configuration.rb | 42 +++++++++++++++++-- core/lib/compass/util.rb | 1 + .../projects/relative/css/screen.css | 6 ++- .../relative/sass/_project-setup.scss | 36 +++++++++++++++- .../projects/relative/sass/screen.sass | 7 ++++ .../asset-collection-1/fnt/font-one.woff | 0 .../asset-collection-1/img/image-one.png | 0 .../asset-collection-2/assets/font-two.ttf | 0 .../asset-collection-2/assets/image-two.jpg | 0 .../assets/subdir/image-three.gif | 0 core/test/units/util_test.rb | 12 ++++++ 13 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 core/test/integrations/projects/relative/vendor/asset-collection-1/fnt/font-one.woff create mode 100644 core/test/integrations/projects/relative/vendor/asset-collection-1/img/image-one.png create mode 100644 core/test/integrations/projects/relative/vendor/asset-collection-2/assets/font-two.ttf create mode 100644 core/test/integrations/projects/relative/vendor/asset-collection-2/assets/image-two.jpg create mode 100644 core/test/integrations/projects/relative/vendor/asset-collection-2/assets/subdir/image-three.gif diff --git a/core/lib/compass/configuration.rb b/core/lib/compass/configuration.rb index 4ace707885..8d97b03e42 100644 --- a/core/lib/compass/configuration.rb +++ b/core/lib/compass/configuration.rb @@ -94,6 +94,7 @@ def remove_configuration_property(name) } RUNTIME_READONLY_ATTRIBUTES = [ + :additional_import_paths, :cache, attributes_for_directory(:cache, nil), :chunky_png_options, diff --git a/core/lib/compass/configuration/asset_collection.rb b/core/lib/compass/configuration/asset_collection.rb index 714eb93057..4332612ced 100644 --- a/core/lib/compass/configuration/asset_collection.rb +++ b/core/lib/compass/configuration/asset_collection.rb @@ -115,11 +115,11 @@ class Compass::Configuration::AssetCollection < Compass::Configuration::Abstract # or a lambda or proc that will compute the cache_buster for assets in this collection. # If :http_dir is set instead of http_path, this defaults to the project's asset_cache_buster. def initialize(options, configuration = nil) - symbolize_keys!(options) assert_valid_keys(options, :root_path, :root_dir, :http_path, :http_dir, :sass_dir, :fonts_dir, :http_fonts_dir, :http_fonts_path, :images_dir, :http_images_dir, :http_images_path, :asset_host, :asset_cache_buster) + symbolize_keys!(options) unless options.has_key?(:root_path) || options.has_key?(:root_dir) raise ArgumentError, "Either :root_path or :root_dir must be specified." end diff --git a/core/lib/compass/core/sass_extensions/functions/configuration.rb b/core/lib/compass/core/sass_extensions/functions/configuration.rb index d57e33ce9a..c85d750465 100644 --- a/core/lib/compass/core/sass_extensions/functions/configuration.rb +++ b/core/lib/compass/core/sass_extensions/functions/configuration.rb @@ -83,8 +83,7 @@ def add_sass_configuration(project_path) end declare :add_sass_configuration, [:project_path] - OPTION_TRANSFORMER = Hash.new() {|h, k| proc {|v, ctx| v.value } } - OPTION_TRANSFORMER[:asset_cache_buster] = proc do |v, ctx| + def self.make_cache_buster_proc(v, ctx) proc do |url, file| if ctx.environment.function(v.value) || Sass::Script::Functions.callable?(v.value.tr('-', '_')) result = ctx.call(v, ctx.quoted_string(url), @@ -108,7 +107,8 @@ def add_sass_configuration(project_path) end end end - OPTION_TRANSFORMER[:asset_host] = proc do |v, ctx| + + def self.make_asset_host_proc(v, ctx) proc do |file| if ctx.environment.function(v.value) || Sass::Script::Functions.callable?(v.value.tr('-', '_')) result = ctx.call(v, ctx.quoted_string(file)) @@ -122,6 +122,39 @@ def add_sass_configuration(project_path) raise ArgumentError, "#{v.value} is not a function." end end + + end + + OPTION_TRANSFORMER = Hash.new() {|h, k| proc {|v, ctx| v.value } } + OPTION_TRANSFORMER[:asset_cache_buster] = proc {|v, ctx| make_cache_buster_proc(v, ctx) } + OPTION_TRANSFORMER[:asset_host] = proc {|v, ctx| make_asset_host_proc(v, ctx) } + + OPTION_TRANSFORMER[:asset_collections] = proc do |v, ctx| + v = list([v], :comma) if v.is_a?(Sass::Script::Value::Map) + ctx.assert_type(v, :List) + + asset_collections = [] + + v.value.each do |map| + ctx.assert_type(map, :Map) + asset_collection = {} + map.value.keys.each do |key| + ctx.assert_type key, :String + ctx.assert_type map.value[key], :String unless map.value[key].value.nil? + underscored = key.value.tr("-", "_") + case underscored + when "asset_host" + asset_collection[underscored] = make_asset_host_proc(map.value[key], ctx) + when "asset_cache_buster" + asset_collection[underscored] = make_cache_buster_proc(map.value[key], ctx) + else + asset_collection[underscored] = map.value[key].value + end + end + asset_collections << Compass::Configuration::AssetCollection.new(asset_collection) + end + + asset_collections end def add_configuration(options) @@ -144,7 +177,8 @@ def add_configuration(options) private def runtime_writable_attributes - Compass::Configuration::ATTRIBUTES - Compass::Configuration::RUNTIME_READONLY_ATTRIBUTES + (Compass::Configuration::ATTRIBUTES + Compass::Configuration::ARRAY_ATTRIBUTES) - + Compass::Configuration::RUNTIME_READONLY_ATTRIBUTES end def common_parent_directory(directory1, directory2) diff --git a/core/lib/compass/util.rb b/core/lib/compass/util.rb index f617334605..973f2d2e3f 100644 --- a/core/lib/compass/util.rb +++ b/core/lib/compass/util.rb @@ -17,6 +17,7 @@ def blank?(value) end def assert_valid_keys(hash, *keys) + keys = keys.inject([]) {|m, k| m << k; m << k.to_s if k.is_a?(Symbol); m} invalid_keys = hash.keys - keys if invalid_keys.any? raise ArgumentError, "Invalid key#{'s' if invalid_keys.size > 1} found: #{invalid_keys.map{|k| k.inspect}.join(", ")}" diff --git a/core/test/integrations/projects/relative/css/screen.css b/core/test/integrations/projects/relative/css/screen.css index a076f52a2b..2fa1b9899c 100644 --- a/core/test/integrations/projects/relative/css/screen.css +++ b/core/test/integrations/projects/relative/css/screen.css @@ -1 +1,5 @@ -test { background: url('../assets/images/testing.png?<%= File.mtime(File.join(Compass.configuration.project_path, 'assets', 'images', 'testing.png')).strftime("%s") %>'); } +test { background: url('../assets/images/testing-d41d8cd98f00b204e9800998ecf8427e.png'); } + +.assets-one { font-url: url('../assets-1/fnt/font-one-d41d8cd98f00b204e9800998ecf8427e.woff'); image-url: url('../assets-1/img/image-one-d41d8cd98f00b204e9800998ecf8427e.png'); } + +.assets-two { font-url: url('../assets/d41d8cd98f00b204e9800998ecf8427e.ttf'); image-url: url('../assets/d41d8cd98f00b204e9800998ecf8427e.jpg'); subdir-image-url: url('../assets/d41d8cd98f00b204e9800998ecf8427e.gif'); } diff --git a/core/test/integrations/projects/relative/sass/_project-setup.scss b/core/test/integrations/projects/relative/sass/_project-setup.scss index 52e5e3106d..bb403103f6 100644 --- a/core/test/integrations/projects/relative/sass/_project-setup.scss +++ b/core/test/integrations/projects/relative/sass/_project-setup.scss @@ -2,5 +2,37 @@ $project-path: absolute-path(join-file-segments("..")); @import "compass/configuration"; -@include compass-configuration($images-dir: join-file-segments("assets", "images"), - $relative-assets: true); +@function different-cache-buster($url, $filename) { + $parsed-file: split-filename($url); + $directory: nth($parsed-file, 1); + $base: nth($parsed-file, 2); + $ext: nth($parsed-file, 3); + @return (path: "/assets/#{md5sum($filename)}#{$ext}"); +} + +@function my-cache-buster($url, $filename) { + $parsed-file: split-filename($url); + $directory: nth($parsed-file, 1); + $base: nth($parsed-file, 2); + $ext: nth($parsed-file, 3); + @return (path: "#{$directory}/#{$base}-#{md5sum($filename)}#{$ext}"); +} + +$compass-config: ( + relative-assets: true, + images-dir: join-file-segments("assets", "images"), + asset-cache-buster: my-cache-buster, + asset-collections: ( + (root-dir: join-file-segments("vendor", "asset-collection-1"), + http-dir: "assets-1", + images-dir: img, + fonts-dir: fnt), + (root-dir: join-file-segments("vendor", "asset-collection-2"), + http-dir: "assets-2", + images-dir: assets, + fonts-dir: assets, + asset-cache-buster: different-cache-buster), + ), +); + +@include compass-configuration($compass-config); diff --git a/core/test/integrations/projects/relative/sass/screen.sass b/core/test/integrations/projects/relative/sass/screen.sass index 68078ba1f7..44cc611534 100644 --- a/core/test/integrations/projects/relative/sass/screen.sass +++ b/core/test/integrations/projects/relative/sass/screen.sass @@ -1,3 +1,10 @@ @import "project-setup" test background: image-url("testing.png") +.assets-one + font-url: font-url("font-one.woff") + image-url: image-url("image-one.png") +.assets-two + font-url: font-url("font-two.ttf") + image-url: image-url("image-two.jpg") + subdir-image-url: image-url("subdir/image-three.gif") diff --git a/core/test/integrations/projects/relative/vendor/asset-collection-1/fnt/font-one.woff b/core/test/integrations/projects/relative/vendor/asset-collection-1/fnt/font-one.woff new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/integrations/projects/relative/vendor/asset-collection-1/img/image-one.png b/core/test/integrations/projects/relative/vendor/asset-collection-1/img/image-one.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/integrations/projects/relative/vendor/asset-collection-2/assets/font-two.ttf b/core/test/integrations/projects/relative/vendor/asset-collection-2/assets/font-two.ttf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/integrations/projects/relative/vendor/asset-collection-2/assets/image-two.jpg b/core/test/integrations/projects/relative/vendor/asset-collection-2/assets/image-two.jpg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/integrations/projects/relative/vendor/asset-collection-2/assets/subdir/image-three.gif b/core/test/integrations/projects/relative/vendor/asset-collection-2/assets/subdir/image-three.gif new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/test/units/util_test.rb b/core/test/units/util_test.rb index 030ac1a6ae..5324f7cf8e 100644 --- a/core/test/units/util_test.rb +++ b/core/test/units/util_test.rb @@ -2,6 +2,7 @@ test_directory = File.expand_path(File.dirname(__FILE__)) $: << test_directory unless $:.include? test_directory require 'test_helper' +require 'compass/util' class UtilTest < Test::Unit::TestCase @@ -22,6 +23,17 @@ def test_assert_valid_keys end end + def test_assert_valid_keys_with_symbols_as_strings + Compass::Util.assert_valid_keys({"key1" => true}, :key1, :key2, :key3) + begin + Compass::Util.assert_valid_keys({"key1" => true, "invalid" => true}, :key1, :key2, :key3) + fail "Did not raise" + rescue ArgumentError => e + assert_equal %q{Invalid key found: "invalid"}, e.message + end + end + + private def options From 2ee03e85a84a659695a3c87b4294161e838411bd Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Mon, 25 Aug 2014 15:03:28 -0700 Subject: [PATCH 07/28] Put sass files from an asset collection on the load path. --- cli/test/fixtures/stylesheets/image_urls/config.rb | 7 +++++++ cli/test/fixtures/stylesheets/image_urls/css/screen.css | 2 ++ .../image_urls/other/asset_collection/img/ac-img-1.jpg | 0 .../other/asset_collection/scss/_ac-stylesheet.scss | 1 + cli/test/fixtures/stylesheets/image_urls/sass/screen.sass | 2 ++ core/lib/compass/configuration/adapters.rb | 5 ++++- 6 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 cli/test/fixtures/stylesheets/image_urls/other/asset_collection/img/ac-img-1.jpg create mode 100644 cli/test/fixtures/stylesheets/image_urls/other/asset_collection/scss/_ac-stylesheet.scss diff --git a/cli/test/fixtures/stylesheets/image_urls/config.rb b/cli/test/fixtures/stylesheets/image_urls/config.rb index bcdae437e3..a14b89f388 100644 --- a/cli/test/fixtures/stylesheets/image_urls/config.rb +++ b/cli/test/fixtures/stylesheets/image_urls/config.rb @@ -17,3 +17,10 @@ asset_host do |path| "http://assets%d.example.com" % (path.size % 4) end + +add_asset_collection( + :root_dir => "other/asset_collection", + :http_dir => "ext-assets", + :images_dir => "img", + :sass_dir => "scss" +) diff --git a/cli/test/fixtures/stylesheets/image_urls/css/screen.css b/cli/test/fixtures/stylesheets/image_urls/css/screen.css index 0c01a39183..aa17280efe 100644 --- a/cli/test/fixtures/stylesheets/image_urls/css/screen.css +++ b/cli/test/fixtures/stylesheets/image_urls/css/screen.css @@ -1,3 +1,5 @@ +.imported-from-asset-collection { color: red; } + .showgrid { background-image: url('http://assets0.example.com/images/grid.png?busted=true'); } .inlinegrid { background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAUEAYAAACv1qP4AAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAAZ0lEQVRYw+3QwQ2AIBAFUTEUwI3+uzN7gDscsIgxEuO8An52J11X73OudfxMraXkzHfO3Y98nQEhA0IGhAwIGRAyIGRAyICQASEDQgaEDAgZEDIgZEDIgJABoZzSGK3tPuN9ERFP7Nw4fg+c5g8V1wAAAABJRU5ErkJggg=='); } diff --git a/cli/test/fixtures/stylesheets/image_urls/other/asset_collection/img/ac-img-1.jpg b/cli/test/fixtures/stylesheets/image_urls/other/asset_collection/img/ac-img-1.jpg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cli/test/fixtures/stylesheets/image_urls/other/asset_collection/scss/_ac-stylesheet.scss b/cli/test/fixtures/stylesheets/image_urls/other/asset_collection/scss/_ac-stylesheet.scss new file mode 100644 index 0000000000..2110040da1 --- /dev/null +++ b/cli/test/fixtures/stylesheets/image_urls/other/asset_collection/scss/_ac-stylesheet.scss @@ -0,0 +1 @@ +.imported-from-asset-collection { color: red; } \ No newline at end of file diff --git a/cli/test/fixtures/stylesheets/image_urls/sass/screen.sass b/cli/test/fixtures/stylesheets/image_urls/sass/screen.sass index e16697bcbf..69ee919174 100644 --- a/cli/test/fixtures/stylesheets/image_urls/sass/screen.sass +++ b/cli/test/fixtures/stylesheets/image_urls/sass/screen.sass @@ -1,3 +1,5 @@ +@import "ac-stylesheet" + .showgrid background-image: image-url(unquote("grid.png")) diff --git a/core/lib/compass/configuration/adapters.rb b/core/lib/compass/configuration/adapters.rb index 301fc4a965..af8ae6bef8 100644 --- a/core/lib/compass/configuration/adapters.rb +++ b/core/lib/compass/configuration/adapters.rb @@ -51,7 +51,10 @@ def resolve_additional_import_paths else path end - end + end + + (asset_collections || []).map do |asset_collection| + asset_collection.sass_path + end.compact end def absolute_path?(path) From 6aea71ee65222b3fac273284e1b50a15f982447f Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Tue, 26 Aug 2014 01:06:57 -0700 Subject: [PATCH 08/28] CHANGELOG entry for asset collections. --- compass-style.org/content/CHANGELOG.markdown | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/compass-style.org/content/CHANGELOG.markdown b/compass-style.org/content/CHANGELOG.markdown index 4a7e2610ad..d1abb22f88 100644 --- a/compass-style.org/content/CHANGELOG.markdown +++ b/compass-style.org/content/CHANGELOG.markdown @@ -16,6 +16,22 @@ The Documentation for the [latest preview release](http://beta.compass-style.org Every release contains updated caniuse data unless otherwise noted. +1.1.0 (UNRELEASED) +------------------ + +* Asset Collections - Each asset collection is a bundle of sass stylesheets, + images, and fonts that potentially have their own URL location, cache + busting, and host requirements. Unlike compass extensions, asset + collections don't require the publisher to package their assets + in any particular way and the image and fonts don't need to be bundled + or delivered as part of your projects's assets. + + To add an asset collection to your project, call `add_asset_collection` + and pass the asset collection configuration options to describe where + to find the assets and how the urls for them are constructed. For full + documentation see [XXX](TODO). + + 1.0.1 (08/19/2014) ------------------ From 0d233201c17f22bf70f4c29153e0bacf9d58cc91 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Tue, 26 Aug 2014 11:20:08 -0700 Subject: [PATCH 09/28] Document asset collections. --- compass-style.org/content/CHANGELOG.markdown | 8 ++- .../configuration-reference.markdown | 62 +++++++++++++++++++ .../sass-based-configuration-options.markdown | 8 +++ 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/compass-style.org/content/CHANGELOG.markdown b/compass-style.org/content/CHANGELOG.markdown index d1abb22f88..e94598e1bb 100644 --- a/compass-style.org/content/CHANGELOG.markdown +++ b/compass-style.org/content/CHANGELOG.markdown @@ -24,12 +24,14 @@ Every release contains updated caniuse data unless otherwise noted. busting, and host requirements. Unlike compass extensions, asset collections don't require the publisher to package their assets in any particular way and the image and fonts don't need to be bundled - or delivered as part of your projects's assets. + or delivered as part of your projects's assets. This makes asset + collections ideal for integrating with drupal extensions, bower, and + other front-end packagers. To add an asset collection to your project, call `add_asset_collection` and pass the asset collection configuration options to describe where - to find the assets and how the urls for them are constructed. For full - documentation see [XXX](TODO). + to find the assets and how the urls for them are constructed. [Asset + Collection Documentation](/help/documentation/configuration-reference/#asset-collections). 1.0.1 (08/19/2014) diff --git a/compass-style.org/content/help/documentation/configuration-reference.markdown b/compass-style.org/content/help/documentation/configuration-reference.markdown index 3b83f688b6..f4fe540e9c 100644 --- a/compass-style.org/content/help/documentation/configuration-reference.markdown +++ b/compass-style.org/content/help/documentation/configuration-reference.markdown @@ -389,6 +389,68 @@ To disable the asset cache buster: --- + +**`add_asset_collection`** - Each asset collection is a bundle of sass stylesheets, +images, and fonts that potentially have their own URL location, cache +busting, and host requirements. Unlike compass extensions, asset +collections don't require the publisher to package their assets +in any particular way and the image and fonts don't need to be bundled +or delivered as part of your projects's assets. This makes asset +collections ideal for integrating with drupal extensions, bower, and +other front-end packagers. + +To add an asset collection to your project, call `add_asset_collection` +and pass the asset collection configuration options to describe where +to find the assets and how the urls for them are constructed. The +following options are allowed: + + +* `:root_path` - The absolute path to the asset collection. +* `:root_dir` - A relative path to the asset collection from the project path. +* `:http_path` - Web root location of assets in this collection. + Starts with '/'. +* `:http_dir` - Web root location of assets in this collection. + Relative to the project's `http_path`. +* `:sass_dir` - Sass directory to be added to the Sass import paths. + Relative to the `:root_path` or `:root_dir.` +* `:fonts_dir` - Directory of fonts to be added to the font look up path. + Relative to the `:root_path` or `:root_dir.` +* `:http_fonts_dir` - Where to find fonts on the webserver relative to + the `http_path` or `http_dir.` Defaults to `/`. + Can be overridden by setting `:http_fonts_path`. +* `:http_fonts_path` - Where to find fonts on the webserver. +* `:images_dir` - Directory of images to be added to the image look up path. + Relative to the `:root_path` or `:root_dir.` +* `:http_images_dir` - Where to find images on the webserver relative to + the `http_path` or `http_dir.` Defaults to `/`. + Can be overridden by setting `:http_images_path`. +* `:http_images_path` - Where to find images on the webserver. +* `:asset_host` - A string starting with `'http://'` for a single host, + or a lambda or proc that will compute the asset host for assets in this collection. + If `:http_dir` is set instead of `http_path,` this defaults to the project's `asset_host`. +* `:asset_cache_buster` - A string, `:none`, or + or a lambda or proc that will compute the `cache_buster` for assets in this collection. + If `:http_dir` is set instead of `http_path,` this defaults to the project's `asset_cache_buster`. + +It is required to pass either `:root_path` or `:root_dir` and +`:http_path` or `:http_dir`. + +Example: + + add_asset_collection( + :root_dir => "other/asset_collection", + :http_dir => "ext-assets", + :images_dir => "img", + :sass_dir => "scss" + :asset_cache_buster => proc {|url_path, file| + {:path => "/#{Digest::MD5.file(file)}#{File.extname(url_path)}"} }, + :asset_host => proc {|url_path| + "http://assets#{url_path.hash % 4 + 1}.other-asset-server.com" } + ) + + +--- + **`watch`** -- React to changes to arbitrary files within your project. Can be invoked more than once. Example: diff --git a/compass-style.org/content/help/documentation/sass-based-configuration-options.markdown b/compass-style.org/content/help/documentation/sass-based-configuration-options.markdown index e56bf67212..09ca7e825c 100644 --- a/compass-style.org/content/help/documentation/sass-based-configuration-options.markdown +++ b/compass-style.org/content/help/documentation/sass-based-configuration-options.markdown @@ -22,6 +22,14 @@ The options that can be set via Sass configuration are: containing the keys query and/or path mapped to a string. The string is a simple value to set as the query parameter on all urls, when `null`, the cache busting feature is disabled. +* `asset-collections` - List of Maps. Each map is a set of keys + that describe an asset collection. The keys are basically the same + as for the [ruby configuration of asset + collections](/help/documentation/configuration-reference/#asset-collections) + with the following exceptions: 1. keys can be dashed instead of + underscored. 2. Procs should be function references as described here + for `asset-cache-buster` and `asset-host`. 3. The `sass-dir` option + doesn't work because it must be set up external to the sass file itself. * `asset-host` - Function reference, or `null`. When `null` this feature is disabled (default). A referenced function must accept a single argument (the root relative url) and return a full url (starting with From 63ece54a340102a29114708d916d272b3be8206c Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Tue, 26 Aug 2014 14:31:14 -0700 Subject: [PATCH 10/28] Start 1.1 development. --- cli/VERSION | 2 +- core/VERSION | 2 +- core/test/integrations/projects/compass/sass/support.scss | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/VERSION b/cli/VERSION index 7f207341d5..b5a9b474f6 100644 --- a/cli/VERSION +++ b/cli/VERSION @@ -1 +1 @@ -1.0.1 \ No newline at end of file +1.1.0.alpha.0 diff --git a/core/VERSION b/core/VERSION index 7f207341d5..b5a9b474f6 100644 --- a/core/VERSION +++ b/core/VERSION @@ -1 +1 @@ -1.0.1 \ No newline at end of file +1.1.0.alpha.0 diff --git a/core/test/integrations/projects/compass/sass/support.scss b/core/test/integrations/projects/compass/sass/support.scss index fc8d27694f..aed5f20692 100644 --- a/core/test/integrations/projects/compass/sass/support.scss +++ b/core/test/integrations/projects/compass/sass/support.scss @@ -26,7 +26,7 @@ $some-default-value: some default value; @include test('[variable] $compass-extensions is set and is a map') { @include assert-true(global-variable-exists(compass-extensions)); @include assert-equal(map, type-of($compass-extensions)); - @include assert-equal(1, str-index(map-get($compass-extensions, compass), "1.0")); + @include assert-equal(1, str-index(map-get($compass-extensions, compass), "1.1")); } @include test('[function] set-arglist-default() with no arguments') { @include assert-true( From 8ab4e15fc3ff0c64c0b0d862e15c7e31bb1c4df6 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Tue, 26 Aug 2014 14:51:39 -0700 Subject: [PATCH 11/28] update deploy script --- compass-style.org/.gitignore | 1 - compass-style.org/sync | 10 ++++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100755 compass-style.org/sync diff --git a/compass-style.org/.gitignore b/compass-style.org/.gitignore index 624d6eeb2d..e2188ee05c 100644 --- a/compass-style.org/.gitignore +++ b/compass-style.org/.gitignore @@ -5,5 +5,4 @@ vendor/ruby crash.log tmp .bundle -sync .rvmrc diff --git a/compass-style.org/sync b/compass-style.org/sync new file mode 100755 index 0000000000..6573e418c4 --- /dev/null +++ b/compass-style.org/sync @@ -0,0 +1,10 @@ +rm -rf output +if [[ `bundle exec compass version` == *alpha* ]] +then + SITE=beta.compass-style.org; +else + SITE=compass-style.org; +fi + +echo "Deploying to $SITE" +bundle exec nanoc co && scp -r output/* compassweb@compass-style.org:$SITE/public/ From 2807a160021a3d96def702d2c90052436104aaed Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Tue, 26 Aug 2014 14:52:27 -0700 Subject: [PATCH 12/28] update gemfile --- compass-style.org/Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compass-style.org/Gemfile.lock b/compass-style.org/Gemfile.lock index e331aee2cc..831e87149a 100644 --- a/compass-style.org/Gemfile.lock +++ b/compass-style.org/Gemfile.lock @@ -1,14 +1,14 @@ PATH remote: .. specs: - compass (1.0.1) + compass (1.1.0.alpha.0) chunky_png (~> 1.2) - compass-core (~> 1.0.1) + compass-core (~> 1.1.0.alpha.0) compass-import-once (~> 1.0.5) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9) sass (>= 3.3.13, < 3.5) - compass-core (1.0.1) + compass-core (1.1.0.alpha.0) multi_json (~> 1.0) sass (>= 3.3.0, < 3.5) compass-import-once (1.0.5) From b2b1d07726d07ecd8580c332cd825d71b9ca96c3 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Thu, 4 Sep 2014 11:46:55 -0700 Subject: [PATCH 13/28] Make sprites use asset collections. Allow multiple sprite locations to contribute to a sprite glob. --- .../sass_extensions/functions/sprites.rb | 4 +- .../compass/sass_extensions/sprites/image.rb | 7 +-- .../sass_extensions/sprites/sprite_map.rb | 9 +--- cli/lib/compass/sprite_importer.rb | 46 ++++++++-------- cli/test/units/sprites/sprite_map_test.rb | 2 +- compass-style.org/content/CHANGELOG.markdown | 4 ++ .../content/help/tutorials/spriting.markdown | 16 ++++++ .../compass/configuration/asset_collection.rb | 24 +++++++-- core/lib/compass/configuration/data.rb | 18 +++++++ core/lib/compass/core/asset_url_resolver.rb | 53 +++++++++++++++---- .../sass_extensions/functions/image_size.rb | 7 +-- .../sass_extensions/functions/inline_image.rb | 4 +- core/test/units/asset_collection_test.rb | 26 ++++----- 13 files changed, 146 insertions(+), 74 deletions(-) diff --git a/cli/lib/compass/sass_extensions/functions/sprites.rb b/cli/lib/compass/sass_extensions/functions/sprites.rb index 53eb111278..218ae9665c 100644 --- a/cli/lib/compass/sass_extensions/functions/sprites.rb +++ b/cli/lib/compass/sass_extensions/functions/sprites.rb @@ -120,9 +120,7 @@ def sprite_file(map, sprite) verify_map(map, "sprite") verify_sprite(sprite) if image = map.image_for(sprite.value) - image_path = Pathname.new(File.expand_path(image.file)) - images_path = Pathname.new(File.expand_path(Compass.configuration.images_path)) - quoted_string(image_path.relative_path_from(images_path).to_s) + quoted_string(Compass.configuration.sprite_resolver.relative_path(:image, image.file)) else missing_image!(map, sprite) end diff --git a/cli/lib/compass/sass_extensions/sprites/image.rb b/cli/lib/compass/sass_extensions/sprites/image.rb index 941a3038c7..6f1525ffe2 100644 --- a/cli/lib/compass/sass_extensions/sprites/image.rb +++ b/cli/lib/compass/sass_extensions/sprites/image.rb @@ -30,12 +30,7 @@ def file end def find_file - Compass.configuration.sprite_load_path.compact.each do |path| - f = File.join(path, relative_file) - if File.exists?(f) - return f - end - end + Compass.configuration.sprite_resolver.find_asset(:image, relative_file) end # Width of the image diff --git a/cli/lib/compass/sass_extensions/sprites/sprite_map.rb b/cli/lib/compass/sass_extensions/sprites/sprite_map.rb index d7dcdc6c85..22125ea359 100644 --- a/cli/lib/compass/sass_extensions/sprites/sprite_map.rb +++ b/cli/lib/compass/sass_extensions/sprites/sprite_map.rb @@ -24,14 +24,7 @@ def self.from_uri(uri, context, kwargs) end def self.relative_name(sprite) - sprite = File.expand_path(sprite) - Compass.configuration.sprite_load_path.each do |path| - path_with_slash = "#{File.expand_path(path)}/" - - if sprite.include?(path_with_slash) - return sprite.gsub(path_with_slash, '') - end - end + Compass.configuration.sprite_resolver.relative_path(:image, sprite) end def initialize(sprites, path, name, context, kwargs) diff --git a/cli/lib/compass/sprite_importer.rb b/cli/lib/compass/sprite_importer.rb index ca01b41f4b..22ef671d9d 100644 --- a/cli/lib/compass/sprite_importer.rb +++ b/cli/lib/compass/sprite_importer.rb @@ -5,35 +5,33 @@ class SpriteImporter < Sass::Importers::Base VAILD_FILE_NAME = /\A#{Sass::SCSS::RX::IDENT}\Z/ SPRITE_IMPORTER_REGEX = %r{((.+/)?([^\*.]+))/(.+?)\.png} VALID_EXTENSIONS = ['.png'] - + TEMPLATE_FOLDER = File.join(File.expand_path('../', __FILE__), 'sprite_importer') CONTENT_TEMPLATE_FILE = File.join(TEMPLATE_FOLDER, 'content.erb') CONTENT_TEMPLATE = ERB.new(File.read(CONTENT_TEMPLATE_FILE)) - - # finds all sprite files def self.find_all_sprite_map_files(path) hex = "[0-9a-f]" glob = "*-s#{hex*10}{#{VALID_EXTENSIONS.join(",")}}" Sass::Util.glob(File.join(path, "**", glob)) end - + def find(uri, options) if uri =~ SPRITE_IMPORTER_REGEX return self.class.sass_engine(uri, self.class.sprite_name(uri), self, options) end nil end - + def find_relative(uri, base, options) nil end - + def to_s self.class.name end - + def hash self.class.name.hash end @@ -41,13 +39,13 @@ def hash def eql?(other) other.class == self.class end - + def mtime(uri, options) self.class.files(uri).sort.inject(Time.at(0)) do |max_time, file| (t = File.mtime(file)) > max_time ? t : max_time end end - + def key(uri, options={}) [self.class.name + ":sprite:" + File.dirname(File.expand_path(uri)), File.basename(uri)] end @@ -56,8 +54,7 @@ def public_url(*args) nil end - - def self.path_and_name(uri) + def self.path_and_name(uri) if uri =~ SPRITE_IMPORTER_REGEX [$1, $3] else @@ -76,17 +73,22 @@ def self.path(uri) path, _ = path_and_name(uri) path end - + # Returns the Glob of image files for the uri def self.files(uri) - Compass.configuration.sprite_load_path.compact.each do |folder| - files = Sass::Util.glob(File.join(folder, uri)).sort - next if files.empty? - return files - end - - path = Compass.configuration.sprite_load_path.to_a.join(', ') - raise Compass::SpriteException, %Q{No files were found in the load path matching "#{uri}". Your current load paths are: #{path}} + resolved_files = Compass.configuration.sprite_resolver.glob(:image, uri, :match_all => true) + resolved_files = resolved_files.inject({}) do |basenames, file| + basename = File.basename(file, '.png') + unless basenames.has_key?(basename) + basenames[basename] = true + basenames[:files] ||= [] + basenames[:files] << file + end + basenames + end[:files] + return resolved_files if resolved_files.any? + path = Compass.configuration.sprite_resolver.asset_collections.map{|ac| ac.images_path }.join(", ") + raise Compass::SpriteException, %Q{No images were found in the sprite path matching "#{uri}". Your current load paths are: #{path}} end # Returns an Array of image names without the file extension @@ -95,12 +97,12 @@ def self.sprite_names(uri) File.basename(file, '.png') end end - + # Returns the sass_options for this sprite def self.sass_options(uri, importer, options) options.merge!(:filename => uri.gsub(%r{\*/},"*\\/"), :syntax => :scss, :importer => importer) end - + # Returns a Sass::Engine for this sprite object def self.sass_engine(uri, name, importer, options) content = content_for_images(uri, name, options[:skip_overrides]) diff --git a/cli/test/units/sprites/sprite_map_test.rb b/cli/test/units/sprites/sprite_map_test.rb index dc930607f5..96e8b0c9f7 100644 --- a/cli/test/units/sprites/sprite_map_test.rb +++ b/cli/test/units/sprites/sprite_map_test.rb @@ -162,7 +162,7 @@ def teardown config.sprite_load_path = [@images_tmp_path, other_folder] Compass.add_configuration(config, "sprite_config") image = Compass::SassExtensions::Sprites::Image.new(@base, "foo/my.png", {}) - assert_equal File.join(other_folder, 'foo/my.png'), image.file + assert_equal File.expand_path(File.join(other_folder, 'foo/my.png')), image.file assert_equal 0, image.size end diff --git a/compass-style.org/content/CHANGELOG.markdown b/compass-style.org/content/CHANGELOG.markdown index e94598e1bb..e099458490 100644 --- a/compass-style.org/content/CHANGELOG.markdown +++ b/compass-style.org/content/CHANGELOG.markdown @@ -32,6 +32,10 @@ Every release contains updated caniuse data unless otherwise noted. and pass the asset collection configuration options to describe where to find the assets and how the urls for them are constructed. [Asset Collection Documentation](/help/documentation/configuration-reference/#asset-collections). +* Sprite import globs now match all files found across the project + images directory, all asset collections and the sprite load paths. + If two images have the same basename the first one is kept and the + other(s) discarded according to the order above. 1.0.1 (08/19/2014) diff --git a/compass-style.org/content/help/tutorials/spriting.markdown b/compass-style.org/content/help/tutorials/spriting.markdown index 7b72c35497..fcbf668d5d 100644 --- a/compass-style.org/content/help/tutorials/spriting.markdown +++ b/compass-style.org/content/help/tutorials/spriting.markdown @@ -183,3 +183,19 @@ Or install the Rubygem: gem install oily_png Compass will automatically detect its presence. + +## Sprite Paths + +Sprite source images don't have to only come from your project's image +directory. If you have configured your application to have any [asset +collections](/help/documentation/configuration-reference/#asset-collections), +Then the sprite source images can also come from there. Furthermore, you +can use the `sprite_load_path` configuration setting to list full paths +to directories where sprite source files can be found. + +Sprite import globs match across all of the sprite paths. This makes it +possible to add or replace images to an external sprite map without merging their +directories. When a sprite source image has the same file name as +another image in the sprite, the first file found is used. The search +order is: You project's images directory, asset collections in their +declation order, and then the sprite load paths. diff --git a/core/lib/compass/configuration/asset_collection.rb b/core/lib/compass/configuration/asset_collection.rb index 4332612ced..8f2c4c444b 100644 --- a/core/lib/compass/configuration/asset_collection.rb +++ b/core/lib/compass/configuration/asset_collection.rb @@ -15,6 +15,23 @@ def as_filesystem_path(url_path) end end + def globs?(type, glob) + # Treat root relative urls (without a protocol) like normal if they start with the images path. + asset_http_path = send(:"http_#{type}s_path") + if glob.start_with?("#{asset_http_path}/") + glob = glob[(asset_http_path.size + 1)..-1] + end + fs_glob = as_filesystem_path(glob) + absolute_glob = File.join(send(:"#{type}s_path"), fs_glob) + resolved_files = Dir.glob(absolute_glob) + if resolved_files.any? + [glob, resolved_files] + else + nil + end + + end + def includes_image?(relative_path) # Treat root relative urls (without a protocol) like normal if they start with the images path. if relative_path.start_with?("#{http_images_path}/") @@ -133,6 +150,7 @@ def initialize(options, configuration = nil) def root_path return @root_path if defined?(@root_path) @root_path = @options[:root_path] || File.join(configuration.project_path, @options[:root_dir]) + @root_path = File.expand_path(@root_path) end def http_path @@ -143,14 +161,14 @@ def http_path def sass_path return @sass_path if defined?(@sass_path) @sass_path = if options[:sass_dir] - File.join(root_path, options[:sass_dir]) + File.expand_path File.join(root_path, options[:sass_dir]) end end def images_path return @images_path if defined?(@images_path) @images_path = if options[:images_dir] - File.join(root_path, options[:images_dir]) + File.expand_path File.join(root_path, options[:images_dir]) end end @@ -169,7 +187,7 @@ def http_images_path def fonts_path return @fonts_path if defined?(@fonts_path) @fonts_path = if options[:fonts_dir] - File.join(root_path, options[:fonts_dir]) + File.expand_path File.join(root_path, options[:fonts_dir]) end end diff --git a/core/lib/compass/configuration/data.rb b/core/lib/compass/configuration/data.rb index de94af0b5e..73c634a00c 100644 --- a/core/lib/compass/configuration/data.rb +++ b/core/lib/compass/configuration/data.rb @@ -213,12 +213,30 @@ def relative_assets? end def url_resolver + return @url_resolver if @url_resolver if top_level == self @url_resolver = Compass::Core::AssetUrlResolver.new(asset_collections.to_a, self) else top_level.url_resolver end end + + def sprite_resolver + return @sprite_resolver if @sprite_resolver + if top_level == self + sprite_collections = asset_collections.to_a + sprite_collections += sprite_load_path.to_a.map do |slp| + AssetCollection.new( + :root_path => slp, + :http_path => http_images_path, + :images_dir => "." + ) + end + @sprite_resolver = Compass::Core::AssetUrlResolver.new(sprite_collections, self) + else + top_level.url_resolver + end + end end end end diff --git a/core/lib/compass/core/asset_url_resolver.rb b/core/lib/compass/core/asset_url_resolver.rb index fd9a73bdf9..f5f232ecf4 100644 --- a/core/lib/compass/core/asset_url_resolver.rb +++ b/core/lib/compass/core/asset_url_resolver.rb @@ -27,14 +27,7 @@ def compute_url(type, relative_path, relative_to_css_url = nil, use_cache_buster # pass through fully specified urls return relative_path if relative_path.start_with?("http://") - # If the image has an target reference, remove it (Common with SVG) - clean_relative_path, target = relative_path.split("#", 2) - - # If the image has a query, remove it - clean_relative_path, query = clean_relative_path.split("?", 2) - - # Get rid of silliness in the url - clean_relative_path = expand_url_path(clean_relative_path) + clean_relative_path, query, target = clean_path(relative_path) # Find the asset collection that includes this asset asset_collection, clean_relative_path, real_path = find_collection(type, clean_relative_path) @@ -70,8 +63,50 @@ def compute_url(type, relative_path, relative_to_css_url = nil, use_cache_buster return url end + # Find the real path to a relative asset path + def find_asset(type, relative_path) + clean_relative_path, _, _ = clean_path(relative_path) + _, _, real_path = find_collection(type, clean_relative_path) + return real_path + end + + def relative_path(type, absolute_path) + absolute_path = File.expand_path(absolute_path) + @asset_collections.find do |ac| + asset_path = File.expand_path(ac.send(:"#{type}s_path")) + if absolute_path.start_with?(asset_path+File::SEPARATOR) + return absolute_path[(asset_path+File::SEPARATOR).size..-1] + end + end + nil + end + + def glob(type, glob_expression, options = {}) + match_all = options.fetch(:match_all, false) + resolved_files = [] + @asset_collections.each do |ac| + _, some_resolved_files = ac.globs?(type, glob_expression) + resolved_files += some_resolved_files if some_resolved_files + return resolved_files if resolved_files.any? and !match_all + end + resolved_files + end + protected + def clean_path(relative_path) + # If the image has an target reference, remove it (Common with SVG) + clean_relative_path, target = relative_path.split("#", 2) + + # If the image has a query, remove it + clean_relative_path, query = clean_relative_path.split("?", 2) + + # Get rid of silliness in the url + clean_relative_path = expand_url_path(clean_relative_path) + + [clean_relative_path, query, target] + end + def find_collection(type, relative_path) asset_collection = nil clean_relative_path = nil @@ -98,7 +133,6 @@ def cache_buster(asset_collection, path, real_path) cache_buster = {:query => cache_buster} if cache_buster.is_a?(String) [cache_buster[:path] || path, cache_buster[:query]] end - def compute_cache_buster(asset_collection, path, real_path) file = nil @@ -126,5 +160,4 @@ def default_cache_buster(path, real_path) nil end end - end diff --git a/core/lib/compass/core/sass_extensions/functions/image_size.rb b/core/lib/compass/core/sass_extensions/functions/image_size.rb index fad357d1e5..658d23775e 100644 --- a/core/lib/compass/core/sass_extensions/functions/image_size.rb +++ b/core/lib/compass/core/sass_extensions/functions/image_size.rb @@ -62,12 +62,7 @@ def image_path_for_size(image_file) end def real_path(image_file) - # Compute the real path to the image on the file stystem if the images_dir is set. - if Compass.configuration.images_path - File.join(Compass.configuration.images_path, image_file) - else - File.join(Compass.configuration.project_path, image_file) - end + Compass.configuration.url_resolver.find_asset(:image, image_file) end class JPEG diff --git a/core/lib/compass/core/sass_extensions/functions/inline_image.rb b/core/lib/compass/core/sass_extensions/functions/inline_image.rb index e8baa36c08..663696a950 100644 --- a/core/lib/compass/core/sass_extensions/functions/inline_image.rb +++ b/core/lib/compass/core/sass_extensions/functions/inline_image.rb @@ -2,7 +2,7 @@ module Compass::Core::SassExtensions::Functions::InlineImage def inline_image(path, mime_type = nil) path = path.value - real_path = File.join(Compass.configuration.images_path, path) + real_path = Compass.configuration.url_resolver.find_asset(:image, path) inline_image_string(data(real_path), compute_mime_type(path, mime_type)) end @@ -10,7 +10,7 @@ def inline_font_files(*args) files = [] with_each_font_file(*args) do |path, type| path = path.value - real_path = File.join(Compass.configuration.fonts_path, path) + real_path = Compass.configuration.url_resolver.find_asset(:font, path) data = inline_image_string(data(real_path), compute_mime_type(path)) files << list(data, unquoted_string("format('#{type}')"), :space) end diff --git a/core/test/units/asset_collection_test.rb b/core/test/units/asset_collection_test.rb index 40b183b092..7a15321fbf 100755 --- a/core/test/units/asset_collection_test.rb +++ b/core/test/units/asset_collection_test.rb @@ -89,11 +89,11 @@ def test_resolved_attributes_absolute def test_resolved_attributes_relative collection = AssetCollection.new(RELATIVE_COLLECTION_OPTS) - assert_equal "./some_assets", collection.root_path + assert_equal File.expand_path("./some_assets"), collection.root_path assert_equal "/some-assets", collection.http_path - assert_equal "./some_assets/scss", collection.sass_path - assert_equal "./some_assets/fnts", collection.fonts_path - assert_equal "./some_assets/imgs", collection.images_path + assert_equal File.expand_path("./some_assets/scss"), collection.sass_path + assert_equal File.expand_path("./some_assets/fnts"), collection.fonts_path + assert_equal File.expand_path("./some_assets/imgs"), collection.images_path assert_equal "/some-assets/fnts", collection.http_fonts_path assert_equal "/some-assets/imgs", collection.http_images_path assert_equal nil, collection.asset_host @@ -102,11 +102,11 @@ def test_resolved_attributes_relative def test_resolved_attributes_http_absolute collection = AssetCollection.new(HTTP_ABSOLUTE_COLLECTION_OPTS) - assert_equal "./some_assets", collection.root_path + assert_equal File.expand_path("./some_assets"), collection.root_path assert_equal "/some-assets", collection.http_path - assert_equal "./some_assets/scss", collection.sass_path - assert_equal "./some_assets/fnts", collection.fonts_path - assert_equal "./some_assets/imgs", collection.images_path + assert_equal File.expand_path("./some_assets/scss"), collection.sass_path + assert_equal File.expand_path("./some_assets/fnts"), collection.fonts_path + assert_equal File.expand_path("./some_assets/imgs"), collection.images_path assert_equal "/font-assets", collection.http_fonts_path assert_equal "/image-assets", collection.http_images_path assert_equal nil, collection.asset_host @@ -115,11 +115,11 @@ def test_resolved_attributes_http_absolute def test_resolved_attributes_http_relative collection = AssetCollection.new(HTTP_RELATIVE_COLLECTION_OPTS) - assert_equal "./some_assets", collection.root_path + assert_equal File.expand_path("./some_assets"), collection.root_path assert_equal "/some-assets", collection.http_path - assert_equal "./some_assets/scss", collection.sass_path - assert_equal "./some_assets/fnts", collection.fonts_path - assert_equal "./some_assets/imgs", collection.images_path + assert_equal File.expand_path("./some_assets/scss"), collection.sass_path + assert_equal File.expand_path("./some_assets/fnts"), collection.fonts_path + assert_equal File.expand_path("./some_assets/imgs"), collection.images_path assert_equal "/some-assets/hfnts", collection.http_fonts_path assert_equal "/some-assets/himgs", collection.http_images_path assert_equal nil, collection.asset_host @@ -149,7 +149,7 @@ def test_resolved_attributes_relative_default Compass.configuration.asset_cache_buster(&asset_cache_buster_proc) collection = AssetCollection.new(:root_dir => RELATIVE_COLLECTION_OPTS[:root_dir], :http_dir => RELATIVE_COLLECTION_OPTS[:http_dir]) - assert_equal "./some_assets", collection.root_path + assert_equal File.expand_path("./some_assets"), collection.root_path assert_equal "/some-assets", collection.http_path assert_equal nil, collection.sass_path assert_equal nil, collection.fonts_path From ffc89c6ed979ef36baac73bf78a159280705cee7 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Thu, 4 Sep 2014 12:29:57 -0700 Subject: [PATCH 14/28] Bump version to 1.1.0.alpha.1. --- core/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/VERSION b/core/VERSION index b5a9b474f6..78c1f201ee 100644 --- a/core/VERSION +++ b/core/VERSION @@ -1 +1 @@ -1.1.0.alpha.0 +1.1.0.alpha.1 \ No newline at end of file From 4a1b1c1fd28dd1a94ccfd9f4cf9b8a3d2b97f2e4 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Thu, 4 Sep 2014 12:30:46 -0700 Subject: [PATCH 15/28] Bump version to 1.1.0.alpha.1. --- cli/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/VERSION b/cli/VERSION index b5a9b474f6..78c1f201ee 100644 --- a/cli/VERSION +++ b/cli/VERSION @@ -1 +1 @@ -1.1.0.alpha.0 +1.1.0.alpha.1 \ No newline at end of file From 7214b4ce1d442ff6b2022e086eced51e9ccf87e4 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Thu, 4 Sep 2014 13:51:59 -0700 Subject: [PATCH 16/28] Stable output for this test case. --- core/lib/compass/util.rb | 2 +- core/test/units/util_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/lib/compass/util.rb b/core/lib/compass/util.rb index 973f2d2e3f..29bf725f09 100644 --- a/core/lib/compass/util.rb +++ b/core/lib/compass/util.rb @@ -20,7 +20,7 @@ def assert_valid_keys(hash, *keys) keys = keys.inject([]) {|m, k| m << k; m << k.to_s if k.is_a?(Symbol); m} invalid_keys = hash.keys - keys if invalid_keys.any? - raise ArgumentError, "Invalid key#{'s' if invalid_keys.size > 1} found: #{invalid_keys.map{|k| k.inspect}.join(", ")}" + raise ArgumentError, "Invalid key#{'s' if invalid_keys.size > 1} found: #{invalid_keys.map{|k| k.inspect}.sort.join(", ")}" end end diff --git a/core/test/units/util_test.rb b/core/test/units/util_test.rb index 5324f7cf8e..133a7ec485 100644 --- a/core/test/units/util_test.rb +++ b/core/test/units/util_test.rb @@ -19,7 +19,7 @@ def test_assert_valid_keys :key1, :key2, :key3) fail "Did not raise" rescue ArgumentError => e - assert_equal "Invalid keys found: :invalid, :another_invalid", e.message + assert_equal "Invalid keys found: :another_invalid, :invalid", e.message end end From 2c1907deb30a3ec42313e0a5caa74139892f9459 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Thu, 4 Sep 2014 14:31:53 -0700 Subject: [PATCH 17/28] See if this fixes travis tests. --- cli/lib/compass/sprite_importer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/lib/compass/sprite_importer.rb b/cli/lib/compass/sprite_importer.rb index 22ef671d9d..83f150e264 100644 --- a/cli/lib/compass/sprite_importer.rb +++ b/cli/lib/compass/sprite_importer.rb @@ -86,7 +86,7 @@ def self.files(uri) end basenames end[:files] - return resolved_files if resolved_files.any? + return resolved_files.sort if resolved_files.any? path = Compass.configuration.sprite_resolver.asset_collections.map{|ac| ac.images_path }.join(", ") raise Compass::SpriteException, %Q{No images were found in the sprite path matching "#{uri}". Your current load paths are: #{path}} end From afa32db1758a98f62701c93f305dc05eddfbabda Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Wed, 10 Sep 2014 08:32:10 -0700 Subject: [PATCH 18/28] Add missing require. --- cli/lib/compass.rb | 1 + cli/lib/compass/configuration/helpers.rb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cli/lib/compass.rb b/cli/lib/compass.rb index 77e9be035b..58ff2d8739 100644 --- a/cli/lib/compass.rb +++ b/cli/lib/compass.rb @@ -33,6 +33,7 @@ def lib_directory configuration/file_data app_integration compiler + sass_compiler sprite_importer ).each do |lib| require "compass/#{lib}" diff --git a/cli/lib/compass/configuration/helpers.rb b/cli/lib/compass/configuration/helpers.rb index a9aef82e38..3079f20061 100644 --- a/cli/lib/compass/configuration/helpers.rb +++ b/cli/lib/compass/configuration/helpers.rb @@ -47,11 +47,11 @@ def configure_sass_plugin! else Sass::Plugin.on_updating_stylesheet(&on_saved) end - + Sass::Plugin.on_compilation_error do |e, filename, css| Compass.configuration.run_stylesheet_error(filename, e.message) end - + @callbacks_loaded = true end end From 7d41ee5a9fbbd5aa0f828479c23d9e1725066097 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Wed, 10 Sep 2014 08:33:30 -0700 Subject: [PATCH 19/28] Adding an application integration caused the config file to stop being loaded. >_< --- cli/lib/compass/configuration/helpers.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/lib/compass/configuration/helpers.rb b/cli/lib/compass/configuration/helpers.rb index 3079f20061..7b9099eff4 100644 --- a/cli/lib/compass/configuration/helpers.rb +++ b/cli/lib/compass/configuration/helpers.rb @@ -66,7 +66,7 @@ def add_project_configuration(*args) configuration_file_path = args.shift || detect_configuration_file raise ArgumentError, "Too many arguments" if args.any? - if AppIntegration.default? && data = configuration_for(configuration_file_path, nil, configuration_for(options[:defaults])) + if data = configuration_for(configuration_file_path, nil, configuration_for(options[:defaults])) if data.raw_project_type add_configuration(data.raw_project_type.to_sym) elsif options[:project_type] @@ -75,7 +75,7 @@ def add_project_configuration(*args) add_configuration(:stand_alone) end add_configuration(data) - else + elsif !AppIntegration.default? add_configuration(options[:project_type] || configuration.project_type_without_default || (yield if block_given?) || :stand_alone) end end From f749d49c5a1c503dd1505fed8a81780dc21cdf41 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Wed, 10 Sep 2014 08:34:41 -0700 Subject: [PATCH 20/28] Bump version to 1.1.0.alpha.2. --- core/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/VERSION b/core/VERSION index 78c1f201ee..0831fc2742 100644 --- a/core/VERSION +++ b/core/VERSION @@ -1 +1 @@ -1.1.0.alpha.1 \ No newline at end of file +1.1.0.alpha.2 \ No newline at end of file From e8eed502bf7448ae9f4140557febd00a571644a4 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Wed, 10 Sep 2014 08:35:37 -0700 Subject: [PATCH 21/28] Bump version to 1.1.0.alpha.2. --- cli/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/VERSION b/cli/VERSION index 78c1f201ee..0831fc2742 100644 --- a/cli/VERSION +++ b/cli/VERSION @@ -1 +1 @@ -1.1.0.alpha.1 \ No newline at end of file +1.1.0.alpha.2 \ No newline at end of file From 0f516e67c9461b167c1565079065658000dc1922 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Wed, 17 Sep 2014 12:06:33 -0700 Subject: [PATCH 22/28] Make gradients work with Sass's inspect(). --- .../core/sass_extensions/functions/gradient_support.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/lib/compass/core/sass_extensions/functions/gradient_support.rb b/core/lib/compass/core/sass_extensions/functions/gradient_support.rb index 750df258f3..74aa359b58 100644 --- a/core/lib/compass/core/sass_extensions/functions/gradient_support.rb +++ b/core/lib/compass/core/sass_extensions/functions/gradient_support.rb @@ -293,6 +293,10 @@ def to_s(options = self.options) to_official.to_s end + def to_sass(*args) + to_s(*args) + end + def to_s_prefixed(options = self.options) to_s(options) end @@ -419,6 +423,10 @@ def to_s(options = self.options) s << ")" end + def to_sass(*args) + to_s(*args) + end + standardized_prefix :webkit standardized_prefix :moz standardized_prefix :o From 113a57f85e8396b79957c206671bc45d15f39c63 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Wed, 17 Sep 2014 12:07:09 -0700 Subject: [PATCH 23/28] Fix how asset collections are added so that they use the array proxy correctly. --- core/lib/compass/configuration/data.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/lib/compass/configuration/data.rb b/core/lib/compass/configuration/data.rb index 73c634a00c..2b780c5530 100644 --- a/core/lib/compass/configuration/data.rb +++ b/core/lib/compass/configuration/data.rb @@ -119,8 +119,7 @@ def add_import_path(*paths) # @see AssetCollection#initialize for options def add_asset_collection(options) @url_resolver = nil - @asset_collections ||= [] - @asset_collections << AssetCollection.new(options) + asset_collections << AssetCollection.new(options) end # When called with a block, defines the asset host url to be used. From 35c60cbd0cc6c1a6fdb62c2dcdca27c5b1268e4d Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Wed, 17 Sep 2014 12:06:33 -0700 Subject: [PATCH 24/28] Make gradients work with Sass's inspect(). --- compass-style.org/content/CHANGELOG.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/compass-style.org/content/CHANGELOG.markdown b/compass-style.org/content/CHANGELOG.markdown index 13ced9d35b..e6c6d60b79 100644 --- a/compass-style.org/content/CHANGELOG.markdown +++ b/compass-style.org/content/CHANGELOG.markdown @@ -36,6 +36,7 @@ Every release contains updated caniuse data unless otherwise noted. images directory, all asset collections and the sprite load paths. If two images have the same basename the first one is kept and the other(s) discarded according to the order above. +* Make gradients work properly with Sass's `inspect()` function. 1.0.2 (UNRELEASED) ------------------ From cfcb45b3911e20ba94b6d7615cd6f069af15c409 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Wed, 17 Sep 2014 12:11:16 -0700 Subject: [PATCH 25/28] Bump version to 1.1.0.alpha.3. --- core/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/VERSION b/core/VERSION index 0831fc2742..4c116d1b98 100644 --- a/core/VERSION +++ b/core/VERSION @@ -1 +1 @@ -1.1.0.alpha.2 \ No newline at end of file +1.1.0.alpha.3 \ No newline at end of file From cb4e2a46d8d158f0d6f26b5c96f6e47d399d39d0 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Wed, 17 Sep 2014 12:12:06 -0700 Subject: [PATCH 26/28] Bump version to 1.1.0.alpha.3. --- cli/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/VERSION b/cli/VERSION index 0831fc2742..4c116d1b98 100644 --- a/cli/VERSION +++ b/cli/VERSION @@ -1 +1 @@ -1.1.0.alpha.2 \ No newline at end of file +1.1.0.alpha.3 \ No newline at end of file From 206710ad244403c7e231d1b14d5d72b844de34e4 Mon Sep 17 00:00:00 2001 From: Scott Davis Date: Thu, 2 Oct 2014 10:45:43 -0400 Subject: [PATCH 27/28] fix broken link closes #1840 --- compass-style.org/content/help/tutorials.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compass-style.org/content/help/tutorials.haml b/compass-style.org/content/help/tutorials.haml index 047f8f520d..212c353207 100644 --- a/compass-style.org/content/help/tutorials.haml +++ b/compass-style.org/content/help/tutorials.haml @@ -13,7 +13,7 @@ layout: tutorial ## New to Compass? - If you're new to Compass, you might be interested in [best practices](/help/tutorials/best_practices/), the [configuration reference](/help/tutorials/configuration-reference/), [configurable variables](/help/tutorials/configurable-variables/), + If you're new to Compass, you might be interested in [best practices](/help/tutorials/best_practices/), the [configuration reference](/help/documentation/configuration-reference/), [configurable variables](/help/tutorials/configurable-variables/), or the [command line documentation](/help/tutorials/command-line/). ## Want to contribute? From 3f71cc738c7577e6755111e9ad253b40b8fb8ea3 Mon Sep 17 00:00:00 2001 From: Scott Davis Date: Thu, 9 Oct 2014 14:16:44 -0400 Subject: [PATCH 28/28] added slack --- .travis.yml | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index f797cba1e9..a6a49ad13b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,29 +1,23 @@ language: ruby - rvm: - - 1.8.7 - - 1.9.2 - - 1.9.3 - - jruby-18mode - - jruby-19mode - - rbx - - ree - - 2.0.0 - - 2.1.0 - +- 1.8.7 +- 1.9.2 +- 1.9.3 +- jruby-18mode +- jruby-19mode +- rbx +- ree +- 2.0.0 +- 2.1.0 sudo: false - env: - - CI_TEST=core - - CI_TEST=cli - +- CI_TEST=core +- CI_TEST=cli gemfile: - - core/Gemfile - - cli/gemfiles/sass_3_3.gemfile - - cli/gemfiles/listen_2.gemfile - +- core/Gemfile +- cli/gemfiles/sass_3_3.gemfile +- cli/gemfiles/listen_2.gemfile script: cd $CI_TEST && bundle exec rake - matrix: exclude: - gemfile: cli/gemfiles/sass_3_3.gemfile @@ -122,9 +116,11 @@ matrix: - gemfile: cli/gemfiles/listen_2.gemfile env: CI_TEST=cli rvm: ree - notifications: - irc: {channels: "irc.freenode.org#compass"} + irc: + channels: irc.freenode.org#compass campfire: rooms: secure: GXnvuoZ8BVMv+JwJIBb0Ey1ARbfeypmCvpmynykD5taooedTqwyTeT32jw1YTQAOuBewgeWW1H4bF10ySz0GWmu6X2sNx9CVYT1dFudoMvLtnvEmAe0JyyRuSCBFj45jP21eRUAACltxzyX4q/gh+zRIlaRin9YBo/Xv84gDzLw= + slack: + secure: XFQ/jH2afeRooWHFSdTqG4ht97N/hrGngUrhwYDxZvVzqYm1Whoh11igUbJ01SWp/KTYijql/3OOSbwPyz6dDIb9v/j3EXgq+vv6qWyjMwCl1pFWqabCxQauIw+fqa1vOlE6PEimIIUivQDJ2HDx75nmMAwqO0dqz44Iq5klhUs=