require 'find' require 'open4' require 'watchful/defaultconfiguration' require "commandline" module Watchful def self.each_source_file_in_dir(path = Dir.pwd) Find.find(path) do |filepath| next if FileTest.directory?(filepath) yield(filepath) end end def self.check_for_interrupts begin sleep 1 rescue Interrupt puts # new line exit 0 end end CONFIGURATION_FILE_NAME = 'watchful' def self.load_configuration(path, use_default = false) # todo: more efficient loading of configurations # todo: check that relative paths work on Windows local = File.expand_path("#{path}/#{CONFIGURATION_FILE_NAME}") user = File.expand_path("~/#{CONFIGURATION_FILE_NAME}") if File.exists? local debug "Loading #{local}" load local elsif File.exists? user debug "Loading #{user}" load user end end @files_with_errors = Hash.new # {:path => '', :mtime => ### } def self.watch_files(path) @output_file_extensions = Configuration.active_configuration.actions.collect do |a| a.out end loop do check_for_interrupts each_source_file_in_dir(path) do |file_path| extension = compound_extension_of(file_path) action = Configuration.active_configuration.actions.find { |a| a.input_file? file_path} next if action.nil? output_path = action.output_path_for(file_path) if (!File.exists?(output_path)) or younger_than(file_path, output_path) error_mtime = @files_with_errors[file_path] next if error_mtime && error_mtime >= File.stat(file_path).mtime do_action(file_path, action) end end end end def self.do_action(source_file, action) puts "#{action.name}: #{source_file}" command = action.command_string(source_file) debug "\t#{command}" proc_pid, proc_stdin, proc_stdout, proc_stderr = Open4::popen4(command) proc_ignored, proc_status = Process::waitpid2(proc_pid) error = proc_stderr.gets if proc_status && !error if HAVE_GROWL growl = Growl.new growl.title = action.name growl.message = "#{source_file}" growl.run end @files_with_errors.delete(source_file) else $stderr.puts("ERROR -- #{action.name} -- #{source_file}") $stderr.puts(error) if HAVE_GROWL growl = Growl.new growl.title = "ERROR: #{action.name}" growl.message = error growl.run end @files_with_errors[source_file] = File.stat(source_file).mtime end end end