New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Outdatedness checker detects changed rules, despite rules not being changed #866

Closed
agross opened this Issue Jun 8, 2016 · 25 comments

Comments

Projects
None yet
3 participants
@agross
Contributor

agross commented Jun 8, 2016

Today I was investigating why our builds take a rather long time despite the fact that we didn't change bytes on disk.

Our site has become rather complex and also a bit dynamic, but with the caches warmed we should not have to wait 30 secs just to compile the same output that already sits on disk :-)

Today I added some puts statements to nanoc's outdatedness_checker.rb and found that nanoc thinks our Rules have changed. Our main Rules file include_rules a bunch of other files that contain the actual rules.

Here's some of my output:

Output of rule_memory_differs_for:

[[:snapshot, :raw, true, nil], [:snapshot, :pre, false, nil], [:filter, :tsc, "Tpbv4FX3L15lr3YoTwET58Ck5tw="], [:snapshot, :last, true, "/assets/js/components/contact-channel/contact-channel-link.js.map"]]
[[:snapshot, :raw, true, nil], [:snapshot, :pre, false, nil], [:filter, :tsc, "GnrgXISbUEBu5yAMT01LlhSXFvo="], [:snapshot, :last, true, "/assets/js/components/contact-channel/contact-channel-link.js.map"]]
<Nanoc::Int::ItemRep name="map" binary=true raw_path="output/assets/js/components/contact-channel/contact-channel-link.js.map" item.identifier="/assets/js/components/contact-channel/contact-channel-link.ts">

Output of outdated?:

#<Nanoc::Int::OutdatednessReasons::Generic:0x0000000e1ec090 @message="The rules file has been modified since the last time the site was compiled.">

In this case contact-channel-link.ts is filtered by tsc (TypeScript Compiler) that generates a js and a map file. I verified that they don't change between compilations content-wise (There's also no updated output written by nanoc).

I wonder what Tpbv4FX3L15lr3YoTwET58Ck5tw and GnrgXISbUEBu5yAMT01LlhSXFvo in the output above are supposed to mean. Hashed parameters of ...?

@ddfreyne

This comment has been minimized.

Show comment
Hide comment
@ddfreyne

ddfreyne Jun 8, 2016

Member

Hi! Could you share the source code for the rule that applies to /assets/js/components/contact-channel/contact-channel-link.ts? My assumption is that the arguments to the :tsc filter can’t be reliably checksummed.

Member

ddfreyne commented Jun 8, 2016

Hi! Could you share the source code for the rule that applies to /assets/js/components/contact-channel/contact-channel-link.ts? My assumption is that the arguments to the :tsc filter can’t be reliably checksummed.

@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 8, 2016

Contributor

Hi :-)

I think that hash of filter parameters (?) pointed me in the right direction. We are using tsc_output = Dir.mktmpdir('tsc-') to compile to a separate directory on each run.

#!/usr/bin/env ruby

tsc_output = Dir.mktmpdir('tsc-')

compile '/assets/js/**/*.ts' do
  minify = Nanoc::CoIt::Deployment::BuildEnvironment.optimization_enabled
  filter :tsc, output_dir: tsc_output, minify: minify
end

compile '/assets/js/**/*.ts', rep: :map do
  source_map = !Nanoc::CoIt::Deployment::BuildEnvironment.optimization_enabled
  filter :tsc, output_dir: tsc_output, source_map: source_map
end

route '/assets/js/**/*.ts' do
  "#{item.identifier.without_ext}.js"
end

route '/assets/js/**/*.ts', rep: :map do
  "#{item.identifier.without_ext}.js.map"
end

postprocess do
  FileUtils.rm_rf(tsc_output)
end
Contributor

agross commented Jun 8, 2016

Hi :-)

I think that hash of filter parameters (?) pointed me in the right direction. We are using tsc_output = Dir.mktmpdir('tsc-') to compile to a separate directory on each run.

#!/usr/bin/env ruby

tsc_output = Dir.mktmpdir('tsc-')

compile '/assets/js/**/*.ts' do
  minify = Nanoc::CoIt::Deployment::BuildEnvironment.optimization_enabled
  filter :tsc, output_dir: tsc_output, minify: minify
end

compile '/assets/js/**/*.ts', rep: :map do
  source_map = !Nanoc::CoIt::Deployment::BuildEnvironment.optimization_enabled
  filter :tsc, output_dir: tsc_output, source_map: source_map
end

route '/assets/js/**/*.ts' do
  "#{item.identifier.without_ext}.js"
end

route '/assets/js/**/*.ts', rep: :map do
  "#{item.identifier.without_ext}.js.map"
end

postprocess do
  FileUtils.rm_rf(tsc_output)
end
@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 8, 2016

Contributor

The tsc filter uses an optimization by caching the compiler output. tsc.exe resolves dependent files itself, so we compile once and later get the result of the first and only compilation for other nanoc items.

class Tsc < Nanoc::Filter
  identifier :tsc
  type       :binary

  def run(ts_filename, output_dir: './tmp/tsc-build', source_map: false, minify: false)
    FileUtils.mkdir_p(output_dir)

    compile(output_dir, minify)
    result = js_filename(ts_filename, output_dir, source_map)

    FileUtils.cp result, output_filename
  end

  private

  # Compiles TypeScript into the given output directory
  # @param [String] path to the target directory
  #   tells the TypeScript compiler where the result should be saved
  def compile(output_dir, minify)
    return unless Dir["#{output_dir}/*"].empty?

    args = %W(npm run tsc -- --outDir #{output_dir})
    system(*args.flatten)

    uglify(output_dir) if minify
  end

  def uglify(output_dir)
    Dir["#{output_dir}/**/*.js"].each { |file|
      system("npm run uglifyjs -- #{file} --compress warnings=false --mangle --output #{file}")
    }
  end

  # Gets the filename of the transpiled js result
  # @param [String] path of the TypeScript file beeing compiled
  # @param [String] path to the TypeScript output directory
  # @param [Boolean] indicator if the source-map should be fetched
  def js_filename(ts_filename, output_dir, source_map)
    transpiled_source = ts_filename.sub(Dir.pwd, output_dir)

    File.join(File.dirname(transpiled_source),
              js_ext(transpiled_source, source_map))
  end

  # Sets .js or js.map as file extension
  # @param [String] path of the TypeScript file beeing compiled
  # @param [Boolean] indicator if .map should be added as extension
  def js_ext(filename, source_map)
    File.basename(filename, '.*') + '.js' + (source_map ? '.map' : '')
  end
end

I believe this works similar to your custom Sass filesystem, but tsc is not Ruby, so we can't let it know about nanoc items ;-)

Contributor

agross commented Jun 8, 2016

The tsc filter uses an optimization by caching the compiler output. tsc.exe resolves dependent files itself, so we compile once and later get the result of the first and only compilation for other nanoc items.

class Tsc < Nanoc::Filter
  identifier :tsc
  type       :binary

  def run(ts_filename, output_dir: './tmp/tsc-build', source_map: false, minify: false)
    FileUtils.mkdir_p(output_dir)

    compile(output_dir, minify)
    result = js_filename(ts_filename, output_dir, source_map)

    FileUtils.cp result, output_filename
  end

  private

  # Compiles TypeScript into the given output directory
  # @param [String] path to the target directory
  #   tells the TypeScript compiler where the result should be saved
  def compile(output_dir, minify)
    return unless Dir["#{output_dir}/*"].empty?

    args = %W(npm run tsc -- --outDir #{output_dir})
    system(*args.flatten)

    uglify(output_dir) if minify
  end

  def uglify(output_dir)
    Dir["#{output_dir}/**/*.js"].each { |file|
      system("npm run uglifyjs -- #{file} --compress warnings=false --mangle --output #{file}")
    }
  end

  # Gets the filename of the transpiled js result
  # @param [String] path of the TypeScript file beeing compiled
  # @param [String] path to the TypeScript output directory
  # @param [Boolean] indicator if the source-map should be fetched
  def js_filename(ts_filename, output_dir, source_map)
    transpiled_source = ts_filename.sub(Dir.pwd, output_dir)

    File.join(File.dirname(transpiled_source),
              js_ext(transpiled_source, source_map))
  end

  # Sets .js or js.map as file extension
  # @param [String] path of the TypeScript file beeing compiled
  # @param [Boolean] indicator if .map should be added as extension
  def js_ext(filename, source_map)
    File.basename(filename, '.*') + '.js' + (source_map ? '.map' : '')
  end
end

I believe this works similar to your custom Sass filesystem, but tsc is not Ruby, so we can't let it know about nanoc items ;-)

@gpakosz

This comment has been minimized.

Show comment
Hide comment
@gpakosz

gpakosz Jun 8, 2016

Member

I once worked around a similar issue by aliasing inspect, e.g:

def compass_sass_engine_options
  options = Compass.sass_engine_options

  options[:load_paths].each do |x|
    class << x
      alias _inspect inspect

      def inspect
        _inspect.gsub(/:0x\h+/, '')
      end
    end
  end
  options
end
Member

gpakosz commented Jun 8, 2016

I once worked around a similar issue by aliasing inspect, e.g:

def compass_sass_engine_options
  options = Compass.sass_engine_options

  options[:load_paths].each do |x|
    class << x
      alias _inspect inspect

      def inspect
        _inspect.gsub(/:0x\h+/, '')
      end
    end
  end
  options
end
@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 8, 2016

Contributor

This seems to work:

#!/usr/bin/env ruby

tsc_output = './tmp/tsc-build'

# Clean up before running and after running. A temporary directory will break
# nanoc's outdatedness checker because the path (and thereby cached tsc filter
# args) change with every invocation of `nanoc compile`.
preprocess do
  FileUtils.rm_rf(tsc_output)
end

postprocess do
  FileUtils.rm_rf(tsc_output)
end

compile '/assets/js/**/*.ts' do
  minify = Nanoc::CoIt::Deployment::BuildEnvironment.optimization_enabled
  filter :tsc, output_dir: tsc_output, minify: minify
end

compile '/assets/js/**/*.ts', rep: :map do
  source_map = !Nanoc::CoIt::Deployment::BuildEnvironment.optimization_enabled
  filter :tsc, output_dir: tsc_output, source_map: source_map
end

route '/assets/js/**/*.ts' do
  "#{item.identifier.without_ext}.js"
end

route '/assets/js/**/*.ts', rep: :map do
  "#{item.identifier.without_ext}.js.map"
end
Contributor

agross commented Jun 8, 2016

This seems to work:

#!/usr/bin/env ruby

tsc_output = './tmp/tsc-build'

# Clean up before running and after running. A temporary directory will break
# nanoc's outdatedness checker because the path (and thereby cached tsc filter
# args) change with every invocation of `nanoc compile`.
preprocess do
  FileUtils.rm_rf(tsc_output)
end

postprocess do
  FileUtils.rm_rf(tsc_output)
end

compile '/assets/js/**/*.ts' do
  minify = Nanoc::CoIt::Deployment::BuildEnvironment.optimization_enabled
  filter :tsc, output_dir: tsc_output, minify: minify
end

compile '/assets/js/**/*.ts', rep: :map do
  source_map = !Nanoc::CoIt::Deployment::BuildEnvironment.optimization_enabled
  filter :tsc, output_dir: tsc_output, source_map: source_map
end

route '/assets/js/**/*.ts' do
  "#{item.identifier.without_ext}.js"
end

route '/assets/js/**/*.ts', rep: :map do
  "#{item.identifier.without_ext}.js.map"
end
@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 8, 2016

Contributor

Next issue :-)

We have an item that's completely empty (empty haml file, no metadata). It's causing outdatedness for itself as well a as a bunch of dependent items.

This line evaluates other.nil? == true. I wonder what othermight be. Any pointers?

Contributor

agross commented Jun 8, 2016

Next issue :-)

We have an item that's completely empty (empty haml file, no metadata). It's causing outdatedness for itself as well a as a bunch of dependent items.

This line evaluates other.nil? == true. I wonder what othermight be. Any pointers?

@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 8, 2016

Contributor

Aha:

    # The direct predecessors can include nil, which indicates an item that is
    # no longer present in the site.

Now this gets really strange. I suspect it's our dynamic parts that cause the issue here.

Sorry for spamming, I'm trying to document my findings.

Contributor

agross commented Jun 8, 2016

Aha:

    # The direct predecessors can include nil, which indicates an item that is
    # no longer present in the site.

Now this gets really strange. I suspect it's our dynamic parts that cause the issue here.

Sorry for spamming, I'm trying to document my findings.

@ddfreyne

This comment has been minimized.

Show comment
Hide comment
@ddfreyne

ddfreyne Jun 9, 2016

Member

The tsc_output = './tmp/tsc-build' approach looks good to me! It’ll indeed avoid the problem with passing in ever-changing arguments to #filter.

A nil represents an object that was present in the site the last time the site was compiled, but not anymore. It might be worth logging all references and what object they resolve to here. (A reference is something returned by #reference, and an object can be an item, layout, code snippet, ….)

Member

ddfreyne commented Jun 9, 2016

The tsc_output = './tmp/tsc-build' approach looks good to me! It’ll indeed avoid the problem with passing in ever-changing arguments to #filter.

A nil represents an object that was present in the site the last time the site was compiled, but not anymore. It might be worth logging all references and what object they resolve to here. (A reference is something returned by #reference, and an object can be an item, layout, code snippet, ….)

@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 9, 2016

Contributor

The nilness seems to be related to item we create in a preprocess block. They're available via new_data, but are missing from @objects. I've dumped both collections and clearly see the diff between both.

The objects we create are static, so I wonder why they're missing from @objects.

Nanoc::Int::DependencyStore is created with ~2k objects before we create the items. It seems our new objects never get added. My debug output:

Loading site… done
Compiling site…
DependencyStore#initialize with objects 2434
creating objects...
DependencyStore#data= with objects 2434
Contributor

agross commented Jun 9, 2016

The nilness seems to be related to item we create in a preprocess block. They're available via new_data, but are missing from @objects. I've dumped both collections and clearly see the diff between both.

The objects we create are static, so I wonder why they're missing from @objects.

Nanoc::Int::DependencyStore is created with ~2k objects before we create the items. It seems our new objects never get added. My debug output:

Loading site… done
Compiling site…
DependencyStore#initialize with objects 2434
creating objects...
DependencyStore#data= with objects 2434
@ddfreyne

This comment has been minimized.

Show comment
Hide comment
@ddfreyne

ddfreyne Jun 9, 2016

Member

I was able to reproduce this with a small example, and I’ll try to come up with a fix (though I’m out in the next few days, so it’ll take a while).

The problem also occurs with a fresh site modified with these steps:

  1. Add the preprocess rule:

    preprocess do
      items.create('Hallo', {}, '/hallo.md')
    end
  2. Add <p><%= @items['/hallo.*'].compiled_content %></p> to content/index.html

  3. Update the index compilation rule:

    compile '/**/*.html' do
      filter :erb
      layout '/default.*'
    end
Member

ddfreyne commented Jun 9, 2016

I was able to reproduce this with a small example, and I’ll try to come up with a fix (though I’m out in the next few days, so it’ll take a while).

The problem also occurs with a fresh site modified with these steps:

  1. Add the preprocess rule:

    preprocess do
      items.create('Hallo', {}, '/hallo.md')
    end
  2. Add <p><%= @items['/hallo.*'].compiled_content %></p> to content/index.html

  3. Update the index compilation rule:

    compile '/**/*.html' do
      filter :erb
      layout '/default.*'
    end
@ddfreyne

This comment has been minimized.

Show comment
Hide comment
@ddfreyne

ddfreyne Jun 9, 2016

Member

The show-data does not preprocess and thus shows invalid data (does not show /hallo.md). Additionally, it doesn’t properly show item rep paths and outdatedness, which is a bug.

Member

ddfreyne commented Jun 9, 2016

The show-data does not preprocess and thus shows invalid data (does not show /hallo.md). Additionally, it doesn’t properly show item rep paths and outdatedness, which is a bug.

@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 9, 2016

Contributor

No hurry! Thanks for confirming that this is not our fault :-)

Contributor

agross commented Jun 9, 2016

No hurry! Thanks for confirming that this is not our fault :-)

@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 19, 2016

Contributor

Hello!

As I said in the other ticket I'm currently migrating a 3.8 project to 4.2. This project also suffers from outdatedness. They all seem to be related to sass, despite the file(s) or rules being unchanged. Nanoc reports that the Rules have been changed, but they really haven't. I've dug deep into that nanoc source and found that the stored checksum for the sass filter seems incorrect.

Rules:

compile '/assets/css/app.sass' do
  require 'compass'
  Compass.add_project_configuration('compass-config.rb')
  filter :sass, Compass.sass_engine_options
end

For the first run I deleted ./tmp and changed the Checksummer to use VerboseDigest. My debug output in OutdatednessChecker#rule_memory_differs_for prints something like what follows. It was printed three times but the string lengths differed by a couple of characters. Do you know a good way to diff like git diff --word-diff?

[[:snapshot, :raw, true, nil], [:snapshot, :pre, false, nil], [:filter, :sass, "Hash<Symbol<load_paths>=Array<Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"J/thE-path/web/content/assets/css\u0006:\u0006EF:\u000F@real_rootI\"J/thE-path/web/content/assets/css\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"DC:/Ruby/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets\u0006:\u0006ET:\u000F@real_rootI\"DC:/Ruby/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets\u0006;\aT:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Compass::SpriteImporter<\u0004\bo:\u001CCompass::SpriteImporter\u0000>,>,Symbol<style>=Symbol<expanded>,Symbol<line_comments>=TrueClass<>,Symbol<sourcemap>=Symbol<none>,Symbol<cache>=TrueClass<>,Symbol<cache_location>=String<tmp/sass-cache>,Symbol<compass>=Hash<Symbol<environment>=Symbol<development>,>,Symbol<full_exception>=TrueClass<>,Symbol<debug_info>=TrueClass<>,>"], [:snapshot, :last, true, "/assets/css/app-cbf1e02a860.css"]]

After compilation succeeded and tmp/rule_memory has been created, I started a second run. There was lots of debug output, all with different lengths, that I decided to wrap Sass:

require 'nanoc'

module Nanoc
  module Filters
    class SassWithCompass < Nanoc::Filter
      identifier :sass_with_compass
      type :text

      requires 'compass'

      def run(content, params = {})
        Compass.add_project_configuration(params.delete(:config_file))
        params = params.merge(Compass.sass_engine_options)

        Nanoc::Filters::Sass.new(@assigns).setup_and_run(content, params)
      end
    end
  end
end

Rules:

compile '/assets/css/app.sass' do
  filter :sass_with_compass, config_file: 'compass-config.rb'
end

A rm -rf tmp later I get this output (3 times):

[[:snapshot, :raw, true, nil], [:snapshot, :pre, false, nil], [:filter, :sass_with_compass, "Hash<Symbol<config_file>=String<compass-config.rb>,>"], [:snapshot, :last, true, "/assets/css/app-cbf1e02a860.css"]]

And subsequent runs yield this:

[[:snapshot, :raw, true, nil], [:snapshot, :pre, false, nil], [:filter, :sass_with_compass, "Hash<>"], [:snapshot, :last, true, "/assets/css/app-cbf1e02a860.css"]]
[[:snapshot, :raw, true, nil], [:snapshot, :pre, false, nil], [:filter, :sass_with_compass, "Hash<Symbol<config_file>=String<compass-config.rb>,>"], [:snapshot, :last, true, "/assets/css/app-cbf1e02a860.css"]]

See the Hash<> part in the first line of output? It seems the checksum is stored incorrectly. There's also this bit in tmp/rule_memory:

item_repo:�Nanoc::Identifier�:
@type:  full:@stringI"�/assets/css/app.sass�:�ET:default[ [   :
snapshot:�rawT0[    ;
:�preF0[�:�filter:�sass_with_compassI"�Hash<>�
Contributor

agross commented Jun 19, 2016

Hello!

As I said in the other ticket I'm currently migrating a 3.8 project to 4.2. This project also suffers from outdatedness. They all seem to be related to sass, despite the file(s) or rules being unchanged. Nanoc reports that the Rules have been changed, but they really haven't. I've dug deep into that nanoc source and found that the stored checksum for the sass filter seems incorrect.

Rules:

compile '/assets/css/app.sass' do
  require 'compass'
  Compass.add_project_configuration('compass-config.rb')
  filter :sass, Compass.sass_engine_options
end

For the first run I deleted ./tmp and changed the Checksummer to use VerboseDigest. My debug output in OutdatednessChecker#rule_memory_differs_for prints something like what follows. It was printed three times but the string lengths differed by a couple of characters. Do you know a good way to diff like git diff --word-diff?

[[:snapshot, :raw, true, nil], [:snapshot, :pre, false, nil], [:filter, :sass, "Hash<Symbol<load_paths>=Array<Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"J/thE-path/web/content/assets/css\u0006:\u0006EF:\u000F@real_rootI\"J/thE-path/web/content/assets/css\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"DC:/Ruby/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets\u0006:\u0006ET:\u000F@real_rootI\"DC:/Ruby/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets\u0006;\aT:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\">/thE-path/web/vendor\u0006:\u0006EF:\u000F@real_rootI\">/thE-path/web/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Sass::Importers::Filesystem<\u0004\bo: Sass::Importers::Filesystem\b:\n@rootI\"B/thE-path/web/tmp/vendor\u0006:\u0006EF:\u000F@real_rootI\"B/thE-path/web/tmp/vendor\u0006;\aF:\u0018@same_name_warningso:\bSet\u0006:\n@hash{\u0000>,Compass::SpriteImporter<\u0004\bo:\u001CCompass::SpriteImporter\u0000>,>,Symbol<style>=Symbol<expanded>,Symbol<line_comments>=TrueClass<>,Symbol<sourcemap>=Symbol<none>,Symbol<cache>=TrueClass<>,Symbol<cache_location>=String<tmp/sass-cache>,Symbol<compass>=Hash<Symbol<environment>=Symbol<development>,>,Symbol<full_exception>=TrueClass<>,Symbol<debug_info>=TrueClass<>,>"], [:snapshot, :last, true, "/assets/css/app-cbf1e02a860.css"]]

After compilation succeeded and tmp/rule_memory has been created, I started a second run. There was lots of debug output, all with different lengths, that I decided to wrap Sass:

require 'nanoc'

module Nanoc
  module Filters
    class SassWithCompass < Nanoc::Filter
      identifier :sass_with_compass
      type :text

      requires 'compass'

      def run(content, params = {})
        Compass.add_project_configuration(params.delete(:config_file))
        params = params.merge(Compass.sass_engine_options)

        Nanoc::Filters::Sass.new(@assigns).setup_and_run(content, params)
      end
    end
  end
end

Rules:

compile '/assets/css/app.sass' do
  filter :sass_with_compass, config_file: 'compass-config.rb'
end

A rm -rf tmp later I get this output (3 times):

[[:snapshot, :raw, true, nil], [:snapshot, :pre, false, nil], [:filter, :sass_with_compass, "Hash<Symbol<config_file>=String<compass-config.rb>,>"], [:snapshot, :last, true, "/assets/css/app-cbf1e02a860.css"]]

And subsequent runs yield this:

[[:snapshot, :raw, true, nil], [:snapshot, :pre, false, nil], [:filter, :sass_with_compass, "Hash<>"], [:snapshot, :last, true, "/assets/css/app-cbf1e02a860.css"]]
[[:snapshot, :raw, true, nil], [:snapshot, :pre, false, nil], [:filter, :sass_with_compass, "Hash<Symbol<config_file>=String<compass-config.rb>,>"], [:snapshot, :last, true, "/assets/css/app-cbf1e02a860.css"]]

See the Hash<> part in the first line of output? It seems the checksum is stored incorrectly. There's also this bit in tmp/rule_memory:

item_repo:�Nanoc::Identifier�:
@type:  full:@stringI"�/assets/css/app.sass�:�ET:default[ [   :
snapshot:�rawT0[    ;
:�preF0[�:�filter:�sass_with_compassI"�Hash<>�
@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 22, 2016

Contributor

Found the issue within the Sass wrapper. params.delete modifies the hash that nanoc will use to calculate the checksum for rule_memory. So we store that modified empty hash digest and check it against a hash digest including :config_file on the next run. Which means the filter always causes outdatedness.

I guess Compass.sass_engine_options is modified internally as well (different length in debug output), leading to the same problem.

Is there a specific reason nanoc computes cache digests after a filter is run and checks them against digests before running the next time? (The reason the check needs to run before on the seconds run is obvious :-))

What's also interesting that compilation didn't get faster after fixing the digest by duplicating the params hash. It even got slower than just recompile. Haven't checked because I'm on vacation this week.

Contributor

agross commented Jun 22, 2016

Found the issue within the Sass wrapper. params.delete modifies the hash that nanoc will use to calculate the checksum for rule_memory. So we store that modified empty hash digest and check it against a hash digest including :config_file on the next run. Which means the filter always causes outdatedness.

I guess Compass.sass_engine_options is modified internally as well (different length in debug output), leading to the same problem.

Is there a specific reason nanoc computes cache digests after a filter is run and checks them against digests before running the next time? (The reason the check needs to run before on the seconds run is obvious :-))

What's also interesting that compilation didn't get faster after fixing the digest by duplicating the params hash. It even got slower than just recompile. Haven't checked because I'm on vacation this week.

@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 22, 2016

Contributor

Quick repo:

  1. nanoc create-site test

  2. Edit Rules:

    + class Test < Nanoc::Filter
    +   identifier :test
    +   def run(c, p = {})
    +     p.delete(:test)
    +     c
    +   end
    + end
    
    compile '/**/*.html' do
      filter :test, test: :bar
    +   layout '/default.*'
    end
  3. Run nanoc -V several times and see that output/index.html is recompiled as identical.

Contributor

agross commented Jun 22, 2016

Quick repo:

  1. nanoc create-site test

  2. Edit Rules:

    + class Test < Nanoc::Filter
    +   identifier :test
    +   def run(c, p = {})
    +     p.delete(:test)
    +     c
    +   end
    + end
    
    compile '/**/*.html' do
      filter :test, test: :bar
    +   layout '/default.*'
    end
  3. Run nanoc -V several times and see that output/index.html is recompiled as identical.

@ddfreyne

This comment has been minimized.

Show comment
Hide comment
@ddfreyne

ddfreyne Jun 30, 2016

Member

Hmm, mutating params passed to a filter will indeed be a problem. I’d disallow it entirely, if I could, but I’m not sure that’s realistic.

Does the problem persist if you stop mutating params in params.delete(:config_file)?

Member

ddfreyne commented Jun 30, 2016

Hmm, mutating params passed to a filter will indeed be a problem. I’d disallow it entirely, if I could, but I’m not sure that’s realistic.

Does the problem persist if you stop mutating params in params.delete(:config_file)?

@ddfreyne ddfreyne referenced this issue Jun 30, 2016

Merged

Freeze filter arguments #881

2 of 2 tasks complete
@ddfreyne

This comment has been minimized.

Show comment
Hide comment
@ddfreyne

ddfreyne Jun 30, 2016

Member

#881 is a PR that freezes filter arguments.

Member

ddfreyne commented Jun 30, 2016

#881 is a PR that freezes filter arguments.

@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 30, 2016

Contributor

I found this error because we use Compass with Sass as described here. The Compass.sass_engine_options will be modified by Sass or Compass, however it changes on every invocation of compile proc.

I did a quick test:

compile '/assets/css/app.sass' do
  unless defined? LOADED_DEFAULT_CONFIG
    LOADED_DEFAULT_CONFIG = true
    require 'compass'
    Compass.add_project_configuration('compass-config.rb')
  end

  p = Compass.sass_engine_options.freeze
  p "before", p
  filter :sass, p
  p "after", p

  write item.identifier.without_ext + '.css'
end
± nanoc -V
Loading site… done
Compiling site…
"before"
{:load_paths=>[#<Sass::Importers::Filesystem:0x0000000534ebd0 @root="C:/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @real_root="D:/Dropbox/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x0000000534de10 @root="D:/Users/agross/Downloads/test/vendor", @real_root="D:/Users/agross/Downloads/test/vendor", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x0000000534cd80 @root="D:/Users/agross/Downloads/test/tmp/vendor", @real_root="D:/Users/agross/Downloads/test/tmp/vendor", @same_name_warnings=#<Set: {}>>, #<Compass::SpriteImporter:0x0000000534c948>], :style=>:expanded, :line_comments=>true, :sourcemap=>:none, :cache=>true, :cache_location=>"tmp/sass-cache", :compass=>{:environment=>:development}, :full_exception=>true, :debug_info=>false}
"after"
{:load_paths=>[#<Sass::Importers::Filesystem:0x0000000534ebd0 @root="C:/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @real_root="D:/Dropbox/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x0000000534de10 @root="D:/Users/agross/Downloads/test/vendor", @real_root="D:/Users/agross/Downloads/test/vendor", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x0000000534cd80 @root="D:/Users/agross/Downloads/test/tmp/vendor", @real_root="D:/Users/agross/Downloads/test/tmp/vendor", @same_name_warnings=#<Set: {}>>, #<Compass::SpriteImporter:0x0000000534c948>], :style=>:expanded, :line_comments=>true, :sourcemap=>:none, :cache=>true, :cache_location=>"tmp/sass-cache", :compass=>{:environment=>:development}, :full_exception=>true, :debug_info=>false}
"before"
{:load_paths=>[#<Sass::Importers::Filesystem:0x000000051d1c08 @root="C:/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @real_root="D:/Dropbox/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x000000051d0998 @root="D:/Users/agross/Downloads/test/vendor", @real_root="D:/Users/agross/Downloads/test/vendor", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x000000051d03f8 @root="D:/Users/agross/Downloads/test/tmp/vendor", @real_root="D:/Users/agross/Downloads/test/tmp/vendor", @same_name_warnings=#<Set: {}>>, #<Compass::SpriteImporter:0x0000000604fd98>], :style=>:expanded, :line_comments=>true, :sourcemap=>:none, :cache=>true, :cache_location=>"tmp/sass-cache", :compass=>{:environment=>:development}, :full_exception=>true, :debug_info=>false}
"after"
{:load_paths=>[#<Sass::Importers::Filesystem:0x000000051d1c08 @root="C:/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @real_root="D:/Dropbox/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x000000051d0998 @root="D:/Users/agross/Downloads/test/vendor", @real_root="D:/Users/agross/Downloads/test/vendor", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x000000051d03f8 @root="D:/Users/agross/Downloads/test/tmp/vendor", @real_root="D:/Users/agross/Downloads/test/tmp/vendor", @same_name_warnings=#<Set: {}>>, #<Compass::SpriteImporter:0x0000000604fd98>], :style=>:expanded, :line_comments=>true, :sourcemap=>:none, :cache=>true, :cache_location=>"tmp/sass-cache", :compass=>{:environment=>:development}, :full_exception=>true, :debug_info=>false}

... (several more)

   identical  [2.39s]  output/assets/css/app.css

Site compiled in 5.01s.

See how the first load_paths entry changes

  • from :load_paths=>[#<Sass::Importers::Filesystem:0x0000000534ebd0
  • to :load_paths=>[#<Sass::Importers::Filesystem:0x000000051d1c08
Contributor

agross commented Jun 30, 2016

I found this error because we use Compass with Sass as described here. The Compass.sass_engine_options will be modified by Sass or Compass, however it changes on every invocation of compile proc.

I did a quick test:

compile '/assets/css/app.sass' do
  unless defined? LOADED_DEFAULT_CONFIG
    LOADED_DEFAULT_CONFIG = true
    require 'compass'
    Compass.add_project_configuration('compass-config.rb')
  end

  p = Compass.sass_engine_options.freeze
  p "before", p
  filter :sass, p
  p "after", p

  write item.identifier.without_ext + '.css'
end
± nanoc -V
Loading site… done
Compiling site…
"before"
{:load_paths=>[#<Sass::Importers::Filesystem:0x0000000534ebd0 @root="C:/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @real_root="D:/Dropbox/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x0000000534de10 @root="D:/Users/agross/Downloads/test/vendor", @real_root="D:/Users/agross/Downloads/test/vendor", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x0000000534cd80 @root="D:/Users/agross/Downloads/test/tmp/vendor", @real_root="D:/Users/agross/Downloads/test/tmp/vendor", @same_name_warnings=#<Set: {}>>, #<Compass::SpriteImporter:0x0000000534c948>], :style=>:expanded, :line_comments=>true, :sourcemap=>:none, :cache=>true, :cache_location=>"tmp/sass-cache", :compass=>{:environment=>:development}, :full_exception=>true, :debug_info=>false}
"after"
{:load_paths=>[#<Sass::Importers::Filesystem:0x0000000534ebd0 @root="C:/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @real_root="D:/Dropbox/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x0000000534de10 @root="D:/Users/agross/Downloads/test/vendor", @real_root="D:/Users/agross/Downloads/test/vendor", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x0000000534cd80 @root="D:/Users/agross/Downloads/test/tmp/vendor", @real_root="D:/Users/agross/Downloads/test/tmp/vendor", @same_name_warnings=#<Set: {}>>, #<Compass::SpriteImporter:0x0000000534c948>], :style=>:expanded, :line_comments=>true, :sourcemap=>:none, :cache=>true, :cache_location=>"tmp/sass-cache", :compass=>{:environment=>:development}, :full_exception=>true, :debug_info=>false}
"before"
{:load_paths=>[#<Sass::Importers::Filesystem:0x000000051d1c08 @root="C:/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @real_root="D:/Dropbox/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x000000051d0998 @root="D:/Users/agross/Downloads/test/vendor", @real_root="D:/Users/agross/Downloads/test/vendor", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x000000051d03f8 @root="D:/Users/agross/Downloads/test/tmp/vendor", @real_root="D:/Users/agross/Downloads/test/tmp/vendor", @same_name_warnings=#<Set: {}>>, #<Compass::SpriteImporter:0x0000000604fd98>], :style=>:expanded, :line_comments=>true, :sourcemap=>:none, :cache=>true, :cache_location=>"tmp/sass-cache", :compass=>{:environment=>:development}, :full_exception=>true, :debug_info=>false}
"after"
{:load_paths=>[#<Sass::Importers::Filesystem:0x000000051d1c08 @root="C:/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @real_root="D:/Dropbox/Ruby/lib/ruby/gems/2.3.0/gems/compass-core-1.0.3/stylesheets", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x000000051d0998 @root="D:/Users/agross/Downloads/test/vendor", @real_root="D:/Users/agross/Downloads/test/vendor", @same_name_warnings=#<Set: {}>>, #<Sass::Importers::Filesystem:0x000000051d03f8 @root="D:/Users/agross/Downloads/test/tmp/vendor", @real_root="D:/Users/agross/Downloads/test/tmp/vendor", @same_name_warnings=#<Set: {}>>, #<Compass::SpriteImporter:0x0000000604fd98>], :style=>:expanded, :line_comments=>true, :sourcemap=>:none, :cache=>true, :cache_location=>"tmp/sass-cache", :compass=>{:environment=>:development}, :full_exception=>true, :debug_info=>false}

... (several more)

   identical  [2.39s]  output/assets/css/app.css

Site compiled in 5.01s.

See how the first load_paths entry changes

  • from :load_paths=>[#<Sass::Importers::Filesystem:0x0000000534ebd0
  • to :load_paths=>[#<Sass::Importers::Filesystem:0x000000051d1c08
@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 30, 2016

Contributor

Even this will always recompiles the Sass file:

compile '/assets/css/app.sass' do
  unless defined? LOADED_DEFAULT_CONFIG
    require 'compass'
    Compass.add_project_configuration('compass-config.rb')
    LOADED_DEFAULT_CONFIG = Compass.sass_engine_options.freeze
  end

  p "before", LOADED_DEFAULT_CONFIG
  filter :sass, LOADED_DEFAULT_CONFIG
  p "after", LOADED_DEFAULT_CONFIG

  write item.identifier.without_ext + '.css'
end
Contributor

agross commented Jun 30, 2016

Even this will always recompiles the Sass file:

compile '/assets/css/app.sass' do
  unless defined? LOADED_DEFAULT_CONFIG
    require 'compass'
    Compass.add_project_configuration('compass-config.rb')
    LOADED_DEFAULT_CONFIG = Compass.sass_engine_options.freeze
  end

  p "before", LOADED_DEFAULT_CONFIG
  filter :sass, LOADED_DEFAULT_CONFIG
  p "after", LOADED_DEFAULT_CONFIG

  write item.identifier.without_ext + '.css'
end
@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jun 30, 2016

Contributor

Does the problem persist if you stop mutating params in params.delete(:config_file)?

In the simple example above (#866 (comment)) the problem no longer occurs. But not so much with Sass + Compass, as stated above.

I have a workaround for my Sass compilation by decorating the Sass filter with my own filter that loads the configuration, so nanoc sees static parameters passed to my wrapping filter.

Contributor

agross commented Jun 30, 2016

Does the problem persist if you stop mutating params in params.delete(:config_file)?

In the simple example above (#866 (comment)) the problem no longer occurs. But not so much with Sass + Compass, as stated above.

I have a workaround for my Sass compilation by decorating the Sass filter with my own filter that loads the configuration, so nanoc sees static parameters passed to my wrapping filter.

@ddfreyne

This comment has been minimized.

Show comment
Hide comment
@ddfreyne

ddfreyne Jul 1, 2016

Member

#884 has a fix for the Sass importer problem.

Member

ddfreyne commented Jul 1, 2016

#884 has a fix for the Sass importer problem.

@ddfreyne

This comment has been minimized.

Show comment
Hide comment
@ddfreyne

ddfreyne Jul 1, 2016

Member

With both #881 and #884, I believe I can consider this issue as closed. Do you agree?

Member

ddfreyne commented Jul 1, 2016

With both #881 and #884, I believe I can consider this issue as closed. Do you agree?

@ddfreyne

This comment has been minimized.

Show comment
Hide comment
@ddfreyne

ddfreyne Jul 1, 2016

Member

I’ve created a separate issue, #885, for the dependency on generated items.

Member

ddfreyne commented Jul 1, 2016

I’ve created a separate issue, #885, for the dependency on generated items.

@ddfreyne

This comment has been minimized.

Show comment
Hide comment
@ddfreyne

ddfreyne Jul 1, 2016

Member

I’ll close this for now, but do let me know if you still experience problems.

Member

ddfreyne commented Jul 1, 2016

I’ll close this for now, but do let me know if you still experience problems.

@ddfreyne ddfreyne closed this Jul 1, 2016

@ddfreyne ddfreyne added this to the 4.2.2 milestone Jul 1, 2016

@agross

This comment has been minimized.

Show comment
Hide comment
@agross

agross Jul 1, 2016

Contributor

With both #881 and #884, I believe I can consider this issue as closed. Do you agree?

👍 Thanks. I'll make life easier for people who use the suggested Compass settings.

Contributor

agross commented Jul 1, 2016

With both #881 and #884, I believe I can consider this issue as closed. Do you agree?

👍 Thanks. I'll make life easier for people who use the suggested Compass settings.

cdchapman added a commit to pentandra/lifepreserver that referenced this issue Oct 25, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment