Created
January 6, 2016 08:45
-
-
Save geekq/87e3fd54d1ebbed9129e to your computer and use it in GitHub Desktop.
Runs a user-defined command when files are modified
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/ruby | |
require 'rubygems' | |
require 'rake' | |
KNOWN_FILE_TYPES = %w(rb txt py yaml erb pp) | |
# Based on work by Mike Clark. | |
# | |
# From http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Monitor/StakingOutFileChanges.rdoc | |
# Modified (with permission) by Geoffrey Grosenbach to call growlnotify for | |
# | |
# rspec and Test::Unit output. | |
# | |
# See the PeepCode screencast on rSpec or other blog articles for instructions on | |
# setting up growlnotify. | |
# gnome notification, default patterns by vladimir@geekq.net | |
EXPIRATION_IN_SECONDS = 20 | |
IMG_FOLDER = '/home/vd/bin/autotest_images' | |
CLEAR_AND_RESET_TERMINAL = "\ec\e[2J" | |
if ARGV.length < 1 | |
puts " | |
Runs a user-defined command when files are modified. | |
Like autotest, but more customizable. This is useful when you want to do | |
something other than run tests. For example, generate a PDF book, run | |
a single test, or run a legacy Test::Unit suite in an app that also | |
has an rSpec suite. | |
Can use Ruby's Dir[] to get file glob. Quote your args to take advantage of this. | |
Usage: | |
#{$0} '<command-to-run>' <files-to-watch...> | |
If files-to-watch is omitted, then files of some known types are watched | |
(s. source for details) | |
Examples: | |
#{$0} 'rake test:recent' **/*.rb | |
# watch all .rb files in subdirectories and runs rake on file change | |
#{$0} './runtests.rb | |
# watch all known file types in subdirectories and run ./runtests.rb on change | |
" | |
exit 1 | |
end | |
$failed = false | |
def growl(title, msg, img, pri=0, sticky="") | |
# system "growlnotify -n autotest --image ~/.autotest_images/#{img} -p #{pri} -m #{msg.inspect} #{title} #{sticky}" | |
img_path = File.join(IMG_FOLDER,img) | |
# puts "\nyad --notification --timeout=10 --text '#{title} - #{msg}' --image=#{img_path} &" | |
# puts "\nnotify-send -t #{EXPIRATION_IN_SECONDS * 1000} -i #{img_path} '#{title}' '#{msg}'" | |
system "yad --notification --timeout=10 --text '#{title} - #{msg}' --image=#{img_path} &" | |
system "notify-send -t #{EXPIRATION_IN_SECONDS * 1000} -i #{img_path} '#{title}' '#{msg}'" | |
end | |
def self.growl_fail(output) | |
$failed = true | |
growl "FAIL", "#{output}", "fail.png", 2 | |
end | |
def self.growl_pass(output) | |
puts "rstakeout.rb - in growl_pass" | |
unless $failed # safeguard - if we already failed we can not show the green light | |
growl "Pass", "#{output}", "pass.png" | |
end | |
end | |
command = ARGV[0] | |
patterns = ARGV[1..-1] | |
if patterns.length == 0 | |
patterns = KNOWN_FILE_TYPES.map {|ext| "**/*.#{ext}"} | |
else | |
patterns = ARGV | |
end | |
puts "Patterns: #{patterns.inspect}" | |
files = {} | |
patterns.each do |arg| | |
Dir[arg].each { |file| | |
files[file] = File.mtime(file) | |
} | |
end | |
puts "Watching #{files.keys.join(', ')}\nFiles: #{files.keys.length}" | |
trap('INT') do | |
puts "\nQuitting..." | |
exit | |
end | |
changed_file = false | |
run_number = 0 | |
loop do | |
begin #if changed_file | |
# clear log file(s) | |
FileList["log/test*.log"].each do |log_file| # or use "log/*.log" | |
f = File.open(log_file, "w") | |
f.close | |
end | |
$logfile = File.open('/tmp/rstakeout.log','w') | |
puts CLEAR_AND_RESET_TERMINAL if run_number > 0 | |
run_number += 1 | |
puts "running #{command}" | |
IO.popen(command) { |f| | |
f.each do |results| | |
puts results | |
if results.include? 'tests' | |
output = results.slice(/(\d+)\s+tests?,\s*(\d+)\s+assertions?,\s*(\d+)\s+failures?(,\s*(\d+)\s+errors)?/) | |
if output | |
puts "rstakeout detected failures, errors: #{$~[3]}, #{$~[5]} " | |
($~[3].to_i + $~[5].to_i) > 0 ? growl_fail(output) : growl_pass(output) | |
end | |
else | |
output = results.slice(/(\d+)\s+examples?,\s*(\d+)\s+failures?(,\s*(\d+)\s+not implemented)?/) | |
if output | |
$~[2].to_i > 0 ? growl_fail(output) : growl_pass(output) | |
end | |
end | |
# for python doctest | |
if results.include? '***Test Failed***' | |
growl_fail(output) | |
end | |
if results.include? 'Test passed.' | |
growl_pass(output) | |
end | |
# for cucumber | |
if results.include? 'Failing Scenarios' | |
growl_fail(output) | |
elsif results =~ /^\d+ scenario \(/ | |
growl_pass(output) | |
end | |
# for JavaScript buster tests | |
$logfile.puts '~' + results | |
if results =~ /\d+ test.*, \d+ assertion.*, \d+ runtim.* .* failure/ | |
growl_fail("JS-failure") | |
elsif results =~ /\.\.\. OK/ | |
$logfile.puts "Detected 'OK'" | |
growl_pass('JS-tests-OK') | |
end | |
# TODO Generic growl notification for other actions | |
end | |
} | |
$logfile.close unless $logfile.closed? | |
puts "=> done" | |
end | |
until changed_file do | |
sleep 1 | |
changed_file, last_changed = files.find { |file, last_changed| | |
File.mtime(file) > last_changed | |
} | |
end | |
while changed_file do # wait until all files were saved and everything calmed down | |
files[changed_file] = File.mtime(changed_file) | |
puts "=> #{changed_file} changed" | |
sleep 2 | |
changed_file, last_changed = files.find { |file, last_changed| | |
File.mtime(file) > last_changed | |
} | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment