From 3fe8f6a6759f8ce102516e46a01c479d0a551124 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Tue, 4 Nov 2008 11:55:57 -0800 Subject: [PATCH] Added a compass command-line option to watch a project and automatically recompile when it changes. Use compass --watch. --- lib/compass/commands/watch_project.rb | 42 ++++++++++++++++++++++++ lib/compass/exec.rb | 47 +++++++++++++++++---------- 2 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 lib/compass/commands/watch_project.rb diff --git a/lib/compass/commands/watch_project.rb b/lib/compass/commands/watch_project.rb new file mode 100644 index 00000000..4fc5ed69 --- /dev/null +++ b/lib/compass/commands/watch_project.rb @@ -0,0 +1,42 @@ +require 'rubygems' +require 'sass' +require 'fileutils' +require 'pathname' +require File.join(File.dirname(__FILE__), 'base') +require File.join(File.dirname(__FILE__), 'update_project') + +module Compass + module Commands + class WatchProject < UpdateProject + attr_accessor :last_update_time + def perform + super + self.last_update_time = most_recent_update_time + loop do + # TODO: Make this efficient by using filesystem monitoring. + sleep 1 + file, t = should_update? + if t + begin + puts ">>> Change detected to #{file} <<<" + super + rescue StandardError => e + ::Compass::Exec.report_error(e, options) + end + self.last_update_time = t + end + end + end + def most_recent_update_time + Dir.glob(separate("#{project_directory}/src/**/*.sass")).map {|sass_file| File.stat(sass_file).mtime}.max + end + def should_update? + t = most_recent_update_time + if t > last_update_time + file = Dir.glob(separate("#{project_directory}/src/**/*.sass")).detect {|sass_file| File.stat(sass_file).mtime >= t} + [file, t] + end + end + end + end +end \ No newline at end of file diff --git a/lib/compass/exec.rb b/lib/compass/exec.rb index 49dbcad2..3ef1fedf 100644 --- a/lib/compass/exec.rb +++ b/lib/compass/exec.rb @@ -6,6 +6,30 @@ module Compass module Exec class ExecError < StandardError end + + + def report_error(e, options) + $stderr.puts "#{e.class} on line #{get_line e} of #{get_file e}: #{e.message}" + if options[:trace] + e.backtrace[1..-1].each { |t| $stderr.puts " #{t}" } + else + $stderr.puts "Run with --trace to see the full backtrace" + end + end + + def get_file(exception) + exception.backtrace[0].split(/:/, 2)[0] + end + + def get_line(exception) + # SyntaxErrors have weird line reporting + # when there's trailing whitespace, + # which there is for Haml documents. + return exception.message.scan(/:(\d+)/)[0] if exception.is_a?(::Haml::SyntaxError) + exception.backtrace[0].scan(/:(\d+)/)[0] + end + module_function :report_error, :get_file, :get_line + class Compass attr_accessor :args, :options, :opts @@ -24,12 +48,7 @@ module Compass if e.is_a?(ExecError) || e.is_a?(OptionParser::ParseError) $stderr.puts e.message else - $stderr.puts "#{e.class} on line #{get_line e} of #{get_file e}: #{e.message}" - if @options[:trace] - e.backtrace[1..-1].each { |t| $stderr.puts " #{t}" } - else - $stderr.puts "Run with --trace to see the full backtrace" - end + ::Compass::Exec.report_error(e, @options) end exit 1 end @@ -73,6 +92,10 @@ END self.options[:command] = :update_project end + opts.on('-w', '--watch', :NONE, 'Monitor the current project for changes and update') do + self.options[:command] = :watch_project + end + opts.on('-f FRAMEWORK', '--framework FRAMEWORK', [:compass, :blueprint], 'Set up a new project using the selected framework. Legal values: compass (default), blueprint') do |framework| self.options[:framework] = framework end @@ -120,18 +143,6 @@ END self.options[:command] = :print_version end end - - def get_file(exception) - exception.backtrace[0].split(/:/, 2)[0] - end - - def get_line(exception) - # SyntaxErrors have weird line reporting - # when there's trailing whitespace, - # which there is for Haml documents. - return exception.message.scan(/:(\d+)/)[0] if exception.is_a?(::Haml::SyntaxError) - exception.backtrace[0].scan(/:(\d+)/)[0] - end def do_command(command) require File.join(File.dirname(__FILE__), 'commands', command.to_s)