Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'stable'

* stable:
  Fix for strange paths like /path/to/project/./ and /path/to/project/../
  Add a test case to make sure that staleness checks across importers work correctly. Could not reproduce issue. Closes GH-114.
  Don't accidently interpret filenames with glob characters as glob characters during partial lookup.
  • Loading branch information...
commit c041cad208c85248ccfd728f9c0a5ffe9eb9d51a 2 parents 743da17 + 8b66e25
@chriseppstein chriseppstein authored
View
13 lib/sass/importers/filesystem.rb
@@ -13,7 +13,7 @@ class Filesystem < Base
# @param root [String] The root path.
# This importer will import files relative to this path.
def initialize(root)
- @root = root
+ @root = File.expand_path(root)
end
# @see Base#find_relative
@@ -58,9 +58,8 @@ def eql?(other)
# If a full uri is passed, this removes the root from it
# otherwise returns the name unchanged
def remove_root(name)
- root = @root.end_with?('/') ? @root : @root + '/'
- if name.index(root) == 0
- name[root.length..-1]
+ if name.index(@root + "/") == 0
+ name[(@root.length + 1)..-1]
else
name
end
@@ -85,6 +84,7 @@ def extensions
# The first element of each pair is a filename to look for;
# the second element is the syntax that file would be in (`:sass` or `:scss`).
def possible_files(name)
+ name = escape_glob_characters(name)
dirname, basename, extname = split(name)
sorted_exts = extensions.sort
syntax = extensions[extname]
@@ -93,6 +93,11 @@ def possible_files(name)
sorted_exts.map {|ext, syn| ["#{dirname}/{_,}#{basename}.#{ext}", syn]}
end
+ def escape_glob_characters(name)
+ name.gsub(/[\*\[\]\{\}\?]/) do |char|
+ "\\#{char}"
+ end
+ end
REDUNDANT_DIRECTORY = %r{#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}}
# Given a base directory and an `@import`ed name,
View
18 test/sass/engine_test.rb
@@ -57,12 +57,7 @@ class SassEngineTest < Test::Unit::TestCase
"& a\n :b c" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 1],
"a\n :b\n c" => "Illegal nesting: Only properties may be nested beneath properties.",
"$a: b\n :c d\n" => "Illegal nesting: Nothing may be nested beneath variable declarations.",
- "@import foo.sass" => "File to import not found or unreadable: foo.sass.",
"$a: b\n :c d\n" => "Illegal nesting: Nothing may be nested beneath variable declarations.",
- "@import foo.sass" => <<MSG,
-File to import not found or unreadable: foo.sass.
-Load path: .
-MSG
"@import templates/basic\n foo" => "Illegal nesting: Nothing may be nested beneath import directives.",
"foo\n @import foo.css" => "CSS import directives may only be used at the root of a document.",
"@if true\n @import foo" => "Import directives may not be used within control directives or mixins.",
@@ -579,12 +574,21 @@ def test_sass_pathname_import
assert File.exists?(sassc_file)
end
+ def test_nonexistent_import
+ assert_raise_message(Sass::SyntaxError, <<ERR.rstrip) do
+File to import not found or unreadable: nonexistent.sass.
+Load path: #{Dir.pwd}
+ERR
+ render("@import nonexistent.sass")
+ end
+ end
+
def test_nonexistent_extensionless_import
assert_raise_message(Sass::SyntaxError, <<ERR.rstrip) do
File to import not found or unreadable: nonexistent.
-Load path: .
+Load path: #{Dir.pwd}
ERR
- assert_equal("@import url(nonexistent.css);\n", render("@import nonexistent"))
+ render("@import nonexistent")
end
end
View
1  test/sass/fixtures/test_staleness_check_across_importers.css
@@ -0,0 +1 @@
+.pear { color: green; }
View
1  test/sass/fixtures/test_staleness_check_across_importers.scss
@@ -0,0 +1 @@
+@import "apple";
View
103 test/sass/importer_test.rb
@@ -2,6 +2,8 @@
require File.dirname(__FILE__) + '/../test_helper'
require File.dirname(__FILE__) + '/test_helper'
+require 'sass/plugin'
+
class ImporterTest < Test::Unit::TestCase
class FruitImporter < Sass::Importers::Base
@@ -38,6 +40,72 @@ def extensions
end
end
+ # This importer maps one import to another import
+ # based on the mappings passed to importer's constructor.
+ class IndirectImporter < Sass::Importers::Base
+ def initialize(mappings, mtimes)
+ @mappings = mappings
+ @mtimes = mtimes
+ end
+ def find_relative(uri, base, options)
+ nil
+ end
+ def find(name, options)
+ if @mappings.has_key?(name)
+ Sass::Engine.new(
+ %Q[@import "#{@mappings[name]}";],
+ options.merge(
+ :filename => name,
+ :syntax => :scss,
+ :importer => self
+ )
+ )
+ end
+ end
+ def mtime(uri, options)
+ @mtimes.fetch(uri, @mtimes.has_key?(uri) ? Time.now : nil)
+ end
+ def key(uri, options)
+ [self.class.name, uri]
+ end
+ def to_s
+ "IndirectImporter(#{@mappings.keys.join(", ")})"
+ end
+ end
+
+ # This importer maps the import to single class
+ # based on the mappings passed to importer's constructor.
+ class ClassImporter < Sass::Importers::Base
+ def initialize(mappings, mtimes)
+ @mappings = mappings
+ @mtimes = mtimes
+ end
+ def find_relative(uri, base, options)
+ nil
+ end
+ def find(name, options)
+ if @mappings.has_key?(name)
+ Sass::Engine.new(
+ %Q[.#{name}{#{@mappings[name]}}],
+ options.merge(
+ :filename => name,
+ :syntax => :scss,
+ :importer => self
+ )
+ )
+ end
+ end
+ def mtime(uri, options)
+ @mtimes.fetch(uri, @mtimes.has_key?(uri) ? Time.now : nil)
+ end
+ def key(uri, options)
+ [self.class.name, uri]
+ end
+ def to_s
+ "ClassImporter(#{@mappings.keys.join(", ")})"
+ end
+ end
+
def test_can_resolve_generated_imports
scss_file = %Q{
$pear-color: green;
@@ -79,4 +147,39 @@ def test_extension_overrides
ensure
FileUtils.rm_rf(absolutize("tmp"))
end
+
+ def test_staleness_check_across_importers
+ file_system_importer = Sass::Importers::Filesystem.new(fixture_dir)
+ # Make sure the first import is older
+ indirect_importer = IndirectImporter.new({"apple" => "pear"}, {"apple" => Time.now - 1})
+ # Make css file is newer so the dependencies are the only way for the css file to be out of date.
+ FileUtils.touch(fixture_file("test_staleness_check_across_importers.css"))
+ # Make sure the first import is older
+ class_importer = ClassImporter.new({"pear" => %Q{color: green;}}, {"pear" => Time.now + 1})
+
+ options = {
+ :style => :compact,
+ :filename => fixture_file("test_staleness_check_across_importers.scss"),
+ :importer => file_system_importer,
+ :load_paths => [file_system_importer, indirect_importer, class_importer],
+ :syntax => :scss
+ }
+
+ assert_equal File.read(fixture_file("test_staleness_check_across_importers.css")),
+ Sass::Engine.new(File.read(fixture_file("test_staleness_check_across_importers.scss")), options).render
+
+ checker = Sass::Plugin::StalenessChecker.new(options)
+
+ assert checker.stylesheet_needs_update?(
+ fixture_file("test_staleness_check_across_importers.css"),
+ fixture_file("test_staleness_check_across_importers.scss"),
+ file_system_importer
+ )
+ end
+ def fixture_dir
+ File.join(File.dirname(__FILE__), "fixtures")
+ end
+ def fixture_file(path)
+ File.join(fixture_dir, path)
+ end
end
Please sign in to comment.
Something went wrong with that request. Please try again.