watchful 0.0.0.pre1 → 0.0.1.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/.autotest +7 -0
- data/.gitignore +3 -0
- data/README.md +44 -35
- data/Rakefile +17 -19
- data/VERSION +1 -1
- data/bin/watchful +28 -26
- data/lib/watchful.rb +12 -0
- data/lib/watchful/action.rb +16 -8
- data/lib/watchful/configuration.rb +8 -8
- data/lib/watchful/defaultconfiguration.rb +5 -5
- data/lib/watchful/paths.rb +1 -0
- data/lib/watchful/watch.rb +70 -28
- data/test/unit/action_test.rb +68 -0
- data/test/unit/configuration_test.rb +39 -0
- data/test/unit/paths_test.rb +48 -0
- data/test/unit/watch_test.rb +81 -0
- metadata +31 -42
- data/doc/DSL-Specification.rb +0 -51
- data/test/action_test.rb +0 -159
- data/test/configuration_test.rb +0 -80
- data/test/customconfiguration_test.rb +0 -20
- data/test/paths_test.rb +0 -63
- data/test/test_helper.rb +0 -13
- data/watchful.gemspec +0 -78
data/lib/watchful/paths.rb
CHANGED
data/lib/watchful/watch.rb
CHANGED
@@ -12,15 +12,6 @@ module Watchful
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
def self.check_for_interrupts
|
16
|
-
begin
|
17
|
-
sleep 1
|
18
|
-
rescue Interrupt
|
19
|
-
puts # new line
|
20
|
-
exit 0
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
15
|
CONFIGURATION_FILE_NAME = 'watchful'
|
25
16
|
|
26
17
|
def self.load_configuration(path, use_default = false)
|
@@ -32,49 +23,100 @@ module Watchful
|
|
32
23
|
user = File.expand_path("~/#{CONFIGURATION_FILE_NAME}")
|
33
24
|
|
34
25
|
if File.exists? local
|
35
|
-
|
26
|
+
puts "=> Loading configuration #{local}"
|
36
27
|
load local
|
37
28
|
elsif File.exists? user
|
38
|
-
|
29
|
+
puts "=> Loading configuration #{user}"
|
39
30
|
load user
|
40
31
|
end
|
41
32
|
|
42
33
|
end
|
43
34
|
|
35
|
+
# If a tool returns an error code when running, don’t run the tool on the
|
36
|
+
# file again until the source file has been saved again. Otherwise the error
|
37
|
+
# will be repeated every time the errant source file is traversed.
|
44
38
|
@files_with_errors = Hash.new # {:path => '', :mtime => ### }
|
45
39
|
|
46
|
-
def self.watch_files(path)
|
47
|
-
|
48
|
-
|
40
|
+
def self.watch_files(path, force_polling = false)
|
41
|
+
|
42
|
+
if force_polling
|
43
|
+
use_fsevents = false
|
44
|
+
elsif RUBY_PLATFORM.include?('darwin') # todo: better check for OS fsevents support
|
45
|
+
begin
|
46
|
+
require 'fsevents'
|
47
|
+
use_fsevents = true
|
48
|
+
rescue LoadError
|
49
|
+
use_fsevents = false
|
50
|
+
puts
|
51
|
+
puts "*****************************************************************"
|
52
|
+
puts "* Using fsevents significantly improves Watchful’s performance. *"
|
53
|
+
puts "* *"
|
54
|
+
puts "* Install it with: *"
|
55
|
+
puts "* *"
|
56
|
+
puts "* sudo gem install fsevents *"
|
57
|
+
puts "* *"
|
58
|
+
puts "*****************************************************************"
|
59
|
+
puts
|
60
|
+
end
|
49
61
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
62
|
+
|
63
|
+
puts "... Watching #{path} ..."
|
64
|
+
|
65
|
+
if use_fsevents # OS X filesystem events API
|
66
|
+
|
67
|
+
begin
|
68
|
+
|
69
|
+
fsevents_stream = FSEvents::Stream.watch(path) do |events|
|
70
|
+
events.modified_files.each do |file|
|
71
|
+
action = Configuration.active_configuration.action_for_file(file)
|
72
|
+
do_action(file, action) unless action.nil?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
fsevents_stream.run
|
76
|
+
|
77
|
+
rescue Interrupt
|
78
|
+
fsevents_stream.stop
|
79
|
+
end
|
80
|
+
|
81
|
+
else # stat polling
|
82
|
+
|
83
|
+
begin
|
84
|
+
loop do
|
85
|
+
check_for_interrupts
|
86
|
+
each_source_file_in_dir(path) do |file_path|
|
87
|
+
|
88
|
+
extension = compound_extension_of(file_path)
|
89
|
+
|
90
|
+
action = Configuration.active_configuration.action_for_file(file_path)
|
54
91
|
|
55
|
-
|
92
|
+
next if action.nil?
|
56
93
|
|
57
|
-
|
94
|
+
output_path = action.output_path_for(file_path)
|
58
95
|
|
59
|
-
|
96
|
+
if (!File.exists?(output_path)) or younger_than(file_path, output_path)
|
97
|
+
error_mtime = @files_with_errors[file_path]
|
98
|
+
next if error_mtime && error_mtime >= File.stat(file_path).mtime
|
99
|
+
do_action(file_path, action)
|
100
|
+
end
|
60
101
|
|
61
|
-
|
62
|
-
error_mtime = @files_with_errors[file_path]
|
63
|
-
next if error_mtime && error_mtime >= File.stat(file_path).mtime
|
64
|
-
do_action(file_path, action)
|
102
|
+
end
|
65
103
|
end
|
66
|
-
|
104
|
+
rescue Interrupt
|
105
|
+
# pass
|
67
106
|
end
|
107
|
+
|
68
108
|
end
|
109
|
+
|
69
110
|
end
|
70
111
|
|
112
|
+
# apply an action to a change file and post notifications
|
71
113
|
def self.do_action(source_file, action)
|
72
114
|
|
73
|
-
puts "#{action.name}: #{source_file}"
|
115
|
+
puts "! #{action.name}: #{source_file}"
|
74
116
|
|
75
117
|
command = action.command_string(source_file)
|
76
118
|
|
77
|
-
|
119
|
+
puts "!\t#{command}"
|
78
120
|
|
79
121
|
proc_pid, proc_stdin, proc_stdout, proc_stderr = Open4::popen4(command)
|
80
122
|
proc_ignored, proc_status = Process::waitpid2(proc_pid)
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require "watchful/action"
|
4
|
+
|
5
|
+
class TestWatchfulAction < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_construction
|
8
|
+
assert_equal Watchful::Action.new(:name => 'test', :out => '.out').enabled?,
|
9
|
+
false,
|
10
|
+
'Disable new action w/o @in'
|
11
|
+
assert_equal Watchful::Action.new(:name => 'test', :in => '.in').enabled?,
|
12
|
+
false,
|
13
|
+
'Disable new action w/o @out'
|
14
|
+
assert_equal Watchful::Action.new(:name => 'test', :in => '.in', :out => '.out').enabled?,
|
15
|
+
false,
|
16
|
+
'Disable new action w/o @command'
|
17
|
+
assert_equal Watchful::Action.new(
|
18
|
+
:name => 'test', :in => '.in', :out => '.out',
|
19
|
+
:command => 'blargh %s %s', :dependencies => ['blargh']
|
20
|
+
).enabled?,
|
21
|
+
false,
|
22
|
+
'Disable new action w/ missing dependencies'
|
23
|
+
assert Watchful::Action.new(
|
24
|
+
:name => 'a', :in => ".in", :out => ".out", :command => "cat %s > %s"
|
25
|
+
),
|
26
|
+
'Successful creation'
|
27
|
+
assert_raise ArgumentError do
|
28
|
+
Watchful::Action.new :dependencies => Hash.new
|
29
|
+
end
|
30
|
+
assert Watchful::Action.new(
|
31
|
+
:name => 'a', :in => ".in", :out => ".out", :command => "cat %s > %s"
|
32
|
+
).enabled?,
|
33
|
+
'Complete action is enabled'
|
34
|
+
assert Watchful::Action.new(
|
35
|
+
:name => 'a', :in => ".in", :out => ".out"
|
36
|
+
).enabled? == false,
|
37
|
+
'Incomplete action is disabled'
|
38
|
+
assert Watchful::Action.new(
|
39
|
+
:name => 'a', :in => ".in", :command => "cat %s > %s"
|
40
|
+
).enabled? == false,
|
41
|
+
'Incomplete action is disabled'
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_have_command
|
45
|
+
assert Watchful::Action.have_command? 'cat'
|
46
|
+
assert Watchful::Action.have_command? 'echo'
|
47
|
+
assert Watchful::Action.have_command? 'less'
|
48
|
+
assert_equal (Watchful::Action.have_command? 'asdfjkasdf'), false
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_paths_computations
|
52
|
+
a = Watchful::Action.new :name => "Test Action",
|
53
|
+
:in => ".in",
|
54
|
+
:out => ".out",
|
55
|
+
:command => "cat %s > %s",
|
56
|
+
:dependencies => ['cat']
|
57
|
+
assert a.input_file?('/test.in')
|
58
|
+
assert_equal a.input_file?('/test.blah'), false
|
59
|
+
assert a.output_file?('/test.out')
|
60
|
+
assert_equal a.output_file?('/test.blah'), false
|
61
|
+
assert_equal a.output_path_for('/tmp/test.in'), '/tmp/test.out'
|
62
|
+
assert_equal a.command_string('/tmp/test.in'), 'cat /tmp/test.in > /tmp/test.out'
|
63
|
+
assert_raise ArgumentError do
|
64
|
+
a.output_path_for('/test.someother')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require "watchful/configuration"
|
4
|
+
|
5
|
+
class TestWatchfulConfiguration < Test::Unit::TestCase
|
6
|
+
|
7
|
+
class FirstConf < Watchful::Configuration; action :name => 'Placeholder Action'; end
|
8
|
+
|
9
|
+
def test_action_added
|
10
|
+
assert FirstConf.actions.length == 1
|
11
|
+
end
|
12
|
+
|
13
|
+
DESC = 'This is a test'
|
14
|
+
|
15
|
+
class SecondTestConfiguration < Watchful::Configuration; description DESC; end
|
16
|
+
|
17
|
+
def test_description
|
18
|
+
assert SecondTestConfiguration._description == DESC
|
19
|
+
end
|
20
|
+
|
21
|
+
class ThirdConfig < Watchful::Configuration
|
22
|
+
action :key => "First"
|
23
|
+
action :name => "Second"
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_multiple_actions
|
27
|
+
assert ThirdConfig.actions.length == 2
|
28
|
+
end
|
29
|
+
|
30
|
+
class FourthConfig < Watchful::Configuration
|
31
|
+
action :name => 'One', :in => ".one", :out => ".one.out", :command => "cat %s > %s"
|
32
|
+
action :name => 'Two', :in => ".two", :out => ".two.out", :command => "cat %s > %s"
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_action_for_file
|
36
|
+
assert FourthConfig.action_for_file('test.two')
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require "watchful/paths"
|
4
|
+
|
5
|
+
require "fileutils"
|
6
|
+
|
7
|
+
class TestWatchfulPaths < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@testfiles = ['/tmp/a', '/tmp/b']
|
11
|
+
@testfiles.each do |f|
|
12
|
+
FileUtils.touch f
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_younger_than
|
17
|
+
|
18
|
+
sleep 1
|
19
|
+
FileUtils.touch @testfiles[0]
|
20
|
+
assert Watchful.younger_than(@testfiles[0], @testfiles[1]), 'Compares mtimes'
|
21
|
+
|
22
|
+
sleep 1
|
23
|
+
FileUtils.touch @testfiles[1]
|
24
|
+
assert Watchful.younger_than(@testfiles[1], @testfiles[0]), 'Compares mtimes'
|
25
|
+
|
26
|
+
assert_raises Exception do
|
27
|
+
Watchful.younger_than(@testfiles[1], '/asdfasdf/asdfasdf')
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_raises Exception do
|
31
|
+
Watchful.younger_than('/asdfasdf/asdfasdf', @testfiles[1])
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_compound_extension_of
|
37
|
+
|
38
|
+
assert_equal Watchful.compound_extension_of('test.min.css'), '.min.css', 'Compound extension'
|
39
|
+
|
40
|
+
assert_equal Watchful.compound_extension_of('test.css'), '.css', 'Simple extension'
|
41
|
+
|
42
|
+
assert_nil Watchful.compound_extension_of('test'), 'File with no extension'
|
43
|
+
|
44
|
+
assert_nil Watchful.compound_extension_of('.test'), '.profile type'
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require "watchful/watch"
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
class TestWatchfulWatch < Test::Unit::TestCase
|
8
|
+
|
9
|
+
TMPDIR = '/tmp/watchfultest'
|
10
|
+
|
11
|
+
def test_each_source_file_in_dir
|
12
|
+
|
13
|
+
FileUtils.rm_r(TMPDIR) if File.directory?(TMPDIR)
|
14
|
+
|
15
|
+
Dir.mkdir(TMPDIR)
|
16
|
+
|
17
|
+
FileUtils.touch("#{TMPDIR}/a.txt")
|
18
|
+
FileUtils.touch("#{TMPDIR}/b.txt")
|
19
|
+
Dir.mkdir("#{TMPDIR}/subdir")
|
20
|
+
|
21
|
+
found_files = []
|
22
|
+
|
23
|
+
Watchful::each_source_file_in_dir(TMPDIR) { |f| found_files << f }
|
24
|
+
|
25
|
+
assert found_files.include? "#{TMPDIR}/a.txt"
|
26
|
+
assert found_files.include? "#{TMPDIR}/b.txt"
|
27
|
+
assert_equal found_files.length, 2
|
28
|
+
|
29
|
+
FileUtils.rm_r(TMPDIR)
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
USER_CONFIG = File.expand_path("~/#{Watchful::CONFIGURATION_FILE_NAME}")
|
34
|
+
USER_CONFIG_BACKUP = File.expand_path("~/#{Watchful::CONFIGURATION_FILE_NAME}.backup")
|
35
|
+
|
36
|
+
def test_load_configuration
|
37
|
+
|
38
|
+
# preserve existing user config file
|
39
|
+
replace_config = File.exists?(USER_CONFIG)
|
40
|
+
FileUtils.mv(USER_CONFIG, USER_CONFIG_BACKUP) if replace_config
|
41
|
+
|
42
|
+
FileUtils.rm_r(TMPDIR) if File.directory?(TMPDIR)
|
43
|
+
Dir.mkdir(TMPDIR)
|
44
|
+
|
45
|
+
Watchful::load_configuration(TMPDIR, false)
|
46
|
+
assert_equal Watchful::Configuration.active_configuration, Watchful::DefaultConfiguration
|
47
|
+
|
48
|
+
|
49
|
+
File.open("#{TMPDIR}/#{Watchful::CONFIGURATION_FILE_NAME}", 'w') do |f|
|
50
|
+
f.write <<-eos
|
51
|
+
class Conf < Watchful::Configuration
|
52
|
+
description 'the key'
|
53
|
+
action :name => 'test action'
|
54
|
+
end
|
55
|
+
eos
|
56
|
+
end
|
57
|
+
Watchful::load_configuration(TMPDIR, false)
|
58
|
+
assert_equal Watchful::Configuration.active_configuration._description, 'the key'
|
59
|
+
FileUtils.rm("#{TMPDIR}/#{Watchful::CONFIGURATION_FILE_NAME}")
|
60
|
+
|
61
|
+
|
62
|
+
File.open(USER_CONFIG, 'w') do |f|
|
63
|
+
f.write <<-eos
|
64
|
+
class Conf < Watchful::Configuration
|
65
|
+
description 'USER CONFIG'
|
66
|
+
action :name => 'an action'
|
67
|
+
end
|
68
|
+
eos
|
69
|
+
end
|
70
|
+
Watchful::load_configuration(TMPDIR, false)
|
71
|
+
assert_equal Watchful::Configuration.active_configuration._description, 'USER CONFIG'
|
72
|
+
FileUtils.rm(USER_CONFIG)
|
73
|
+
|
74
|
+
FileUtils.rm_r(TMPDIR)
|
75
|
+
FileUtils.mv(USER_CONFIG_BACKUP, USER_CONFIG) if replace_config
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
# todo: find a way to temporarily disable gems while running unit tests
|
80
|
+
|
81
|
+
end
|
metadata
CHANGED
@@ -1,25 +1,25 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: watchful
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
4
|
+
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.0.
|
8
|
+
- 1
|
9
|
+
- 1
|
10
|
+
version: 0.0.1.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
|
-
-
|
13
|
+
- K E Mitchell
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-04-
|
18
|
+
date: 2010-04-23 00:00:00 -05:00
|
19
19
|
default_executable: watchful
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
name:
|
22
|
+
name: commandline
|
23
23
|
prerelease: false
|
24
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
@@ -27,11 +27,13 @@ dependencies:
|
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
segments:
|
29
29
|
- 0
|
30
|
-
|
31
|
-
|
30
|
+
- 7
|
31
|
+
- 10
|
32
|
+
version: 0.7.10
|
33
|
+
type: :runtime
|
32
34
|
version_requirements: *id001
|
33
35
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
36
|
+
name: extensions
|
35
37
|
prerelease: false
|
36
38
|
requirement: &id002 !ruby/object:Gem::Requirement
|
37
39
|
requirements:
|
@@ -39,33 +41,25 @@ dependencies:
|
|
39
41
|
- !ruby/object:Gem::Version
|
40
42
|
segments:
|
41
43
|
- 0
|
42
|
-
|
44
|
+
- 6
|
45
|
+
- 0
|
46
|
+
version: 0.6.0
|
43
47
|
type: :runtime
|
44
48
|
version_requirements: *id002
|
45
49
|
- !ruby/object:Gem::Dependency
|
46
|
-
name:
|
50
|
+
name: open4
|
47
51
|
prerelease: false
|
48
52
|
requirement: &id003 !ruby/object:Gem::Requirement
|
49
53
|
requirements:
|
50
54
|
- - ">="
|
51
55
|
- !ruby/object:Gem::Version
|
52
56
|
segments:
|
57
|
+
- 1
|
53
58
|
- 0
|
54
|
-
|
59
|
+
- 1
|
60
|
+
version: 1.0.1
|
55
61
|
type: :runtime
|
56
62
|
version_requirements: *id003
|
57
|
-
- !ruby/object:Gem::Dependency
|
58
|
-
name: open4
|
59
|
-
prerelease: false
|
60
|
-
requirement: &id004 !ruby/object:Gem::Requirement
|
61
|
-
requirements:
|
62
|
-
- - ">="
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
segments:
|
65
|
-
- 0
|
66
|
-
version: "0"
|
67
|
-
type: :runtime
|
68
|
-
version_requirements: *id004
|
69
63
|
description: Applies intermediary tools to modified files
|
70
64
|
email: kyleevanmitchell@gmail.com
|
71
65
|
executables:
|
@@ -76,25 +70,23 @@ extra_rdoc_files:
|
|
76
70
|
- LICENSE
|
77
71
|
- README.md
|
78
72
|
files:
|
73
|
+
- .autotest
|
79
74
|
- .gitignore
|
80
75
|
- LICENSE
|
81
76
|
- README.md
|
82
77
|
- Rakefile
|
83
78
|
- VERSION
|
84
79
|
- bin/watchful
|
85
|
-
- doc/DSL-Specification.rb
|
86
80
|
- lib/watchful.rb
|
87
81
|
- lib/watchful/action.rb
|
88
82
|
- lib/watchful/configuration.rb
|
89
83
|
- lib/watchful/defaultconfiguration.rb
|
90
84
|
- lib/watchful/paths.rb
|
91
85
|
- lib/watchful/watch.rb
|
92
|
-
- test/action_test.rb
|
93
|
-
- test/configuration_test.rb
|
94
|
-
- test/
|
95
|
-
- test/
|
96
|
-
- test/test_helper.rb
|
97
|
-
- watchful.gemspec
|
86
|
+
- test/unit/action_test.rb
|
87
|
+
- test/unit/configuration_test.rb
|
88
|
+
- test/unit/paths_test.rb
|
89
|
+
- test/unit/watch_test.rb
|
98
90
|
has_rdoc: true
|
99
91
|
homepage: http://github.com/kemitchell/watchful
|
100
92
|
licenses: []
|
@@ -113,13 +105,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
113
105
|
version: "0"
|
114
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
107
|
requirements:
|
116
|
-
- - "
|
108
|
+
- - ">="
|
117
109
|
- !ruby/object:Gem::Version
|
118
110
|
segments:
|
119
|
-
-
|
120
|
-
|
121
|
-
- 1
|
122
|
-
version: 1.3.1
|
111
|
+
- 0
|
112
|
+
version: "0"
|
123
113
|
requirements: []
|
124
114
|
|
125
115
|
rubyforge_project: watchful
|
@@ -128,8 +118,7 @@ signing_key:
|
|
128
118
|
specification_version: 3
|
129
119
|
summary: Watchful, a tool for busy web devs
|
130
120
|
test_files:
|
131
|
-
- test/action_test.rb
|
132
|
-
- test/configuration_test.rb
|
133
|
-
- test/
|
134
|
-
- test/
|
135
|
-
- test/test_helper.rb
|
121
|
+
- test/unit/action_test.rb
|
122
|
+
- test/unit/configuration_test.rb
|
123
|
+
- test/unit/paths_test.rb
|
124
|
+
- test/unit/watch_test.rb
|