sinefunc-rstakeout 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/README.md +27 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/rstakeout +231 -0
- data/data/images/fail.png +0 -0
- data/data/images/ok.png +0 -0
- metadata +70 -0
data/.document
ADDED
data/.gitignore
ADDED
data/README.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Rstakeout
|
2
|
+
=========
|
3
|
+
|
4
|
+
Ruby script to execute an arbitrary command whenever a file changes.
|
5
|
+
|
6
|
+
Forked from github.com/edvardm/rstakeout, which was forked from topfunkyv
|
7
|
+
|
8
|
+
Installation
|
9
|
+
------------
|
10
|
+
|
11
|
+
gem install sinefunc-rstakeout
|
12
|
+
# Mac users: install `growlnotify` from the Growl DWG to get notifications
|
13
|
+
|
14
|
+
Common usage
|
15
|
+
------------
|
16
|
+
|
17
|
+
# Execute a test everytime any file changes
|
18
|
+
rstakeout 'rake test' **/*
|
19
|
+
|
20
|
+
# Regenerate some LessCSS files whenever needed
|
21
|
+
rstakeout 'lessc %s' **/*.less
|
22
|
+
|
23
|
+
Copyright
|
24
|
+
---------
|
25
|
+
|
26
|
+
License: MIT
|
27
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "sinefunc-rstakeout"
|
8
|
+
gem.summary = "Watches a directory for any changes"
|
9
|
+
gem.description = "This gem watches a given directory for any changes and executes a given command when something is changed."
|
10
|
+
gem.email = "rico@sinefunc.com"
|
11
|
+
gem.homepage = "http://github.com/sinefunc/rstakeout"
|
12
|
+
gem.authors = ["edvardw", "topfunky"]
|
13
|
+
#gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
Rake::TestTask.new(:test) do |test|
|
23
|
+
test.libs << 'lib' << 'test'
|
24
|
+
test.pattern = 'test/**/test_*.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rcov/rcovtask'
|
30
|
+
Rcov::RcovTask.new do |test|
|
31
|
+
test.libs << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
task :rcov do
|
37
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
task :test => :check_dependencies
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "rstakeout #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/bin/rstakeout
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
##
|
3
|
+
# Originally by Mike Clark.
|
4
|
+
#
|
5
|
+
# From http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Monitor/StakingOutFileChanges.rdoc
|
6
|
+
#
|
7
|
+
# Runs a user-defined command when files are modified.
|
8
|
+
#
|
9
|
+
# Like autotest, but more customizable. This is useful when you want to do
|
10
|
+
# something other than run tests. For example, generate a PDF book, run
|
11
|
+
# a single test, or run a legacy Test::Unit suite in an app that also
|
12
|
+
# has an rSpec suite.
|
13
|
+
#
|
14
|
+
# Can use Ruby's Dir[] to get file glob. Quote your args to take advantage of this.
|
15
|
+
#
|
16
|
+
# rstakeout 'rake test:recent' **/*.rb
|
17
|
+
# => Only watches Ruby files one directory down (no quotes)
|
18
|
+
#
|
19
|
+
# rstakeout 'rake test:recent' '**/*.rb'
|
20
|
+
# => Watches all Ruby files in all directories and subdirectories
|
21
|
+
#
|
22
|
+
# Modified (with permission) by Geoffrey Grosenbach to call growlnotify for
|
23
|
+
# rspec and Test::Unit output.
|
24
|
+
#
|
25
|
+
# See the PeepCode screencast on rSpec or other blog articles for instructions on
|
26
|
+
# setting up growlnotify.
|
27
|
+
#
|
28
|
+
# * Added Snarl support in win32, initial implementation by Francis Fish
|
29
|
+
# * Added synchronous mode
|
30
|
+
# * Allow adjusting of sleep time
|
31
|
+
# * Fixes to work in Linux env too
|
32
|
+
# Edvard Majakari <edvard@majakari.net>
|
33
|
+
|
34
|
+
prefix = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
35
|
+
Dir["#{prefix}/vendor/*/lib"].each { |dir| $:.unshift dir }
|
36
|
+
|
37
|
+
require 'optparse'
|
38
|
+
require 'ostruct'
|
39
|
+
require 'rubygems'
|
40
|
+
|
41
|
+
def require_gem(gemname)
|
42
|
+
begin
|
43
|
+
require gemname
|
44
|
+
rescue LoadError
|
45
|
+
puts "Please install gem %s" % gemname
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
FAIL_ICON_PATH = File.join(prefix, %w{data images fail.png})
|
51
|
+
OK_ICON_PATH = File.join(prefix, %w{data images ok.png})
|
52
|
+
CHANGED_ICON_PATH = File.join(prefix, %w{data images changed.png})
|
53
|
+
|
54
|
+
module GrowlNotifier
|
55
|
+
class << self
|
56
|
+
def growl_available?
|
57
|
+
@@available = system "which growlnotify > /dev/null"
|
58
|
+
end
|
59
|
+
|
60
|
+
def notify(title, msg, img, pri=0, sticky="")
|
61
|
+
system "growlnotify -n 'rstakeout notification' --image #{img} -p #{pri} -m #{msg.inspect} '#{title}' #{sticky}" if growl_available?
|
62
|
+
end
|
63
|
+
|
64
|
+
private :notify
|
65
|
+
|
66
|
+
def notify_fail(output)
|
67
|
+
notify "Failed", "#{output}", FAIL_ICON_PATH, 2
|
68
|
+
end
|
69
|
+
|
70
|
+
def notify_pass(output)
|
71
|
+
notify "Passed!", "#{output}", OK_ICON_PATH
|
72
|
+
end
|
73
|
+
|
74
|
+
def notify_changed(file)
|
75
|
+
notify "File changed", file, CHANGED_ICON_PATH
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# TODO: instead of begin/rescue, do
|
81
|
+
# module SnarlNotifier < end
|
82
|
+
# module SnarlNotifier::AutoSnarl < end
|
83
|
+
# ?
|
84
|
+
begin
|
85
|
+
module SnarlNotifier
|
86
|
+
# Idea by Francis Fish, http://francis.blog-city.com/
|
87
|
+
begin
|
88
|
+
require 'autotest'
|
89
|
+
rescue Exception
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
include AutoSnarl
|
93
|
+
module ::AutoSnarl
|
94
|
+
def self.snarl(title, msg, ico=nil, timeout=5)
|
95
|
+
Snarl.show_message(title, msg, icon[ico], timeout)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.notify_fail(output)
|
100
|
+
AutoSnarl::snarl "FAIL", "#{output}", :red, 30
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.notify_pass(output)
|
104
|
+
AutoSnarl::snarl "Pass", "#{output}", :green, 10
|
105
|
+
end
|
106
|
+
end
|
107
|
+
rescue Exception
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
|
111
|
+
module EmptyNotifier
|
112
|
+
def self.notify_pass(output)
|
113
|
+
end
|
114
|
+
def self.notify_fail(output)
|
115
|
+
end
|
116
|
+
def self.notify_changed(file)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
Notifier = case RUBY_PLATFORM
|
121
|
+
when /darwin/
|
122
|
+
warn "You can install `growlnotify` for Growl notifications" unless GrowlNotifier.growl_available?
|
123
|
+
GrowlNotifier
|
124
|
+
when /win32/
|
125
|
+
require_gem 'autosnarl'
|
126
|
+
SnarlNotifier
|
127
|
+
else
|
128
|
+
EmptyNotifier
|
129
|
+
end
|
130
|
+
|
131
|
+
module ParseSpecResult
|
132
|
+
def self.notify_test_unit_results(results)
|
133
|
+
output = results.slice(/(\d+)\s+tests?,\s*(\d+)\s+assertions?,\s*(\d+)\s+failures?(,\s*(\d+)\s+errors)?/)
|
134
|
+
if output
|
135
|
+
$~[3].to_i + $~[5].to_i > 0 ? Notifier.notify_fail(output) : Notifier.notify_pass(output)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.notify_rspec_results(results)
|
140
|
+
output = results.slice(/(\d+)\s+examples?,\s*(\d+)\s+failures?(,\s*(\d+)\s+not implemented)?/)
|
141
|
+
if output
|
142
|
+
$~[2].to_i > 0 ? Notifier.notify_fail(output) : Notifier.notify_pass(output)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def build_mtimes_hash(globs)
|
148
|
+
files = {}
|
149
|
+
globs.each { |g|
|
150
|
+
Dir[g].each { |file| files[file] = File.mtime(file) }
|
151
|
+
}
|
152
|
+
files
|
153
|
+
end
|
154
|
+
|
155
|
+
trap('INT') do
|
156
|
+
puts "\nQuitting..."
|
157
|
+
exit
|
158
|
+
end
|
159
|
+
|
160
|
+
options = OpenStruct.new(:sleep_time => 1, :reload_glob => false, :synchronous => false)
|
161
|
+
|
162
|
+
OptionParser.new do |opts|
|
163
|
+
opts.banner = "Usage: rstakeout [options] <command> <filespec>+"
|
164
|
+
opts.on("-t", "--sleep-time T", Integer, "time to sleep after each loop iteration") do |t|
|
165
|
+
options.sleep_time = t
|
166
|
+
end
|
167
|
+
opts.on("-v", "--verbose") do |v|
|
168
|
+
options.verbose = v
|
169
|
+
end
|
170
|
+
opts.on("--sync", "force synchronous mode (disallow simultaneous runs)") do |s|
|
171
|
+
options.synchronous = s
|
172
|
+
end
|
173
|
+
end.parse!
|
174
|
+
|
175
|
+
MYTEMP = ENV['TEMP'] || '/tmp'
|
176
|
+
|
177
|
+
puts ARGV.inspect
|
178
|
+
command = ARGV.shift
|
179
|
+
files = build_mtimes_hash(ARGV)
|
180
|
+
LOCKFILE = File.join(MYTEMP, 'rstakeout.lock')
|
181
|
+
if options.synchronous
|
182
|
+
lock_obj = File.new(LOCKFILE, 'w')
|
183
|
+
end
|
184
|
+
|
185
|
+
if options.verbose
|
186
|
+
p options
|
187
|
+
puts "=> Watching #{files.keys.join(', ')}\n\nFiles: #{files.keys.length}"
|
188
|
+
else
|
189
|
+
puts "=> Watching #{files.keys.length} files... press Ctrl+C to stop."
|
190
|
+
end
|
191
|
+
|
192
|
+
def with_exclusive_lock_if_synchronous(run_synced, lockfile, &block)
|
193
|
+
lockfile.flock(File::LOCK_EX) if run_synced
|
194
|
+
block.call
|
195
|
+
lockfile.flock(File::LOCK_UN) if run_synced
|
196
|
+
end
|
197
|
+
|
198
|
+
loop do
|
199
|
+
changed_file, last_changed = files.find { |file, mtime|
|
200
|
+
begin
|
201
|
+
File.mtime(file) > mtime
|
202
|
+
rescue Errno::ENOENT => e # file may have been moved, deleted etc. while running rstakeout
|
203
|
+
warn e
|
204
|
+
end
|
205
|
+
}
|
206
|
+
|
207
|
+
if changed_file
|
208
|
+
with_exclusive_lock_if_synchronous(options.synchronous, lock_obj) do
|
209
|
+
files[changed_file] = File.mtime(changed_file)
|
210
|
+
|
211
|
+
system "clear"
|
212
|
+
puts "=> `#{changed_file}` changed, running '#{command}'"
|
213
|
+
puts ""
|
214
|
+
|
215
|
+
change_command = command.gsub('%s', changed_file.gsub('"', '\"'))
|
216
|
+
results = `#{change_command} 2>&1`
|
217
|
+
puts results
|
218
|
+
|
219
|
+
if results.include? 'tests'
|
220
|
+
ParseSpecResult.notify_test_unit_results(results)
|
221
|
+
#else
|
222
|
+
# ParseSpecResult.notify_rspec_results(results)
|
223
|
+
elsif $?.to_i > 0
|
224
|
+
Notifier.notify_fail "Error code #{$?.to_i}. See the log for details."
|
225
|
+
else
|
226
|
+
Notifier.notify_pass results
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
sleep options.sleep_time
|
231
|
+
end
|
Binary file
|
data/data/images/ok.png
ADDED
Binary file
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinefunc-rstakeout
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- edvardw
|
13
|
+
- topfunky
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-05-03 00:00:00 +08:00
|
19
|
+
default_executable: rstakeout
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: This gem watches a given directory for any changes and executes a given command when something is changed.
|
23
|
+
email: rico@sinefunc.com
|
24
|
+
executables:
|
25
|
+
- rstakeout
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README.md
|
30
|
+
files:
|
31
|
+
- .document
|
32
|
+
- .gitignore
|
33
|
+
- README.md
|
34
|
+
- Rakefile
|
35
|
+
- VERSION
|
36
|
+
- bin/rstakeout
|
37
|
+
- data/images/fail.png
|
38
|
+
- data/images/ok.png
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://github.com/sinefunc/rstakeout
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options:
|
45
|
+
- --charset=UTF-8
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
segments:
|
53
|
+
- 0
|
54
|
+
version: "0"
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.3.6
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Watches a directory for any changes
|
69
|
+
test_files: []
|
70
|
+
|