Created
July 5, 2017 11:53
-
-
Save geekq/99e52ec674cf769ffa7a4785cf677f0e to your computer and use it in GitHub Desktop.
Watch for source code files to change and rerun the command, supports colors
This file contains hidden or 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 feature j2) | |
| # 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 [email protected] | |
| 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 | |
| # TODO refactor to use trollop for command line switches | |
| simple_mode = !ARGV.delete('--parse-results')# by default just execute with `system` so e.g. the colorful output works | |
| 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 | |
| start_time = Time.now | |
| puts "started at #{start_time.strftime("%H:%M:%S")}" | |
| puts "#{command}" | |
| if simple_mode | |
| system(command) | |
| else | |
| 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 | |
| } | |
| end | |
| $logfile.close unless $logfile.closed? | |
| elapsed = Time.now - start_time | |
| min = elapsed.to_i / 60 | |
| sec = (elapsed - min * 60).round(3) | |
| puts "=> done in #{min}m #{sec}s" | |
| 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