guard 0.7.0.rc1 → 0.7.0
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/CHANGELOG.md +281 -279
- data/LICENSE +19 -19
- data/README.md +487 -487
- data/bin/guard +5 -5
- data/lib/guard.rb +186 -186
- data/lib/guard/cli.rb +90 -90
- data/lib/guard/dsl.rb +148 -148
- data/lib/guard/dsl_describer.rb +28 -28
- data/lib/guard/guard.rb +58 -58
- data/lib/guard/hook.rb +72 -72
- data/lib/guard/interactor.rb +40 -40
- data/lib/guard/listener.rb +191 -191
- data/lib/guard/listeners/darwin.rb +47 -47
- data/lib/guard/listeners/linux.rb +74 -74
- data/lib/guard/listeners/polling.rb +37 -37
- data/lib/guard/listeners/windows.rb +42 -42
- data/lib/guard/notifier.rb +136 -136
- data/lib/guard/templates/Guardfile +2 -2
- data/lib/guard/ui.rb +110 -110
- data/lib/guard/version.rb +3 -3
- data/lib/guard/watcher.rb +66 -66
- data/man/guard.1 +93 -93
- data/man/guard.1.html +176 -176
- metadata +11 -25
- data/lib/guard.rbc +0 -3978
- data/lib/guard/dsl.rbc +0 -3248
- data/lib/guard/dsl_describer.rbc +0 -785
- data/lib/guard/guard.rbc +0 -1007
- data/lib/guard/interactor.rbc +0 -1218
- data/lib/guard/listener.rbc +0 -3507
- data/lib/guard/listeners/darwin.rbc +0 -1106
- data/lib/guard/listeners/linux.rbc +0 -1747
- data/lib/guard/listeners/polling.rbc +0 -775
- data/lib/guard/listeners/windows.rbc +0 -967
- data/lib/guard/notifier.rbc +0 -2994
- data/lib/guard/ui.rbc +0 -2416
- data/lib/guard/version.rbc +0 -180
- data/lib/guard/watcher.rbc +0 -1854
data/lib/guard/hook.rb
CHANGED
@@ -1,72 +1,72 @@
|
|
1
|
-
module Guard
|
2
|
-
module Hook
|
3
|
-
|
4
|
-
def self.included(base)
|
5
|
-
base.send :include, InstanceMethods
|
6
|
-
end
|
7
|
-
|
8
|
-
module InstanceMethods
|
9
|
-
# When +event+ is a Symbol, #hook will generate a hook name
|
10
|
-
# by concatenating the method name from where #hook is called
|
11
|
-
# with the given Symbol.
|
12
|
-
# Example:
|
13
|
-
# def run_all
|
14
|
-
# hook :foo
|
15
|
-
# end
|
16
|
-
# Here, when #run_all is called, #hook will notify callbacks
|
17
|
-
# registered for the "run_all_foo" event.
|
18
|
-
#
|
19
|
-
# When +event+ is a String, #hook will directly turn the String
|
20
|
-
# into a Symbol.
|
21
|
-
# Example:
|
22
|
-
# def run_all
|
23
|
-
# hook "foo_bar"
|
24
|
-
# end
|
25
|
-
# Here, when #run_all is called, #hook will notify callbacks
|
26
|
-
# registered for the "foo_bar" event.
|
27
|
-
#
|
28
|
-
# +args+ parameter is passed as is to the callbacks registered
|
29
|
-
# for the given event.
|
30
|
-
def hook(event, *args)
|
31
|
-
hook_name = if event.is_a? Symbol
|
32
|
-
calling_method = caller[0][/`([^']*)'/, 1]
|
33
|
-
"#{calling_method}_#{event}"
|
34
|
-
else
|
35
|
-
event
|
36
|
-
end.to_sym
|
37
|
-
|
38
|
-
UI.debug "Hook :#{hook_name} executed for #{self.class}"
|
39
|
-
|
40
|
-
Hook.notify(self.class, hook_name, *args)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class << self
|
45
|
-
def callbacks
|
46
|
-
@callbacks ||= Hash.new { |hash, key| hash[key] = [] }
|
47
|
-
end
|
48
|
-
|
49
|
-
def add_callback(listener, guard_class, events)
|
50
|
-
_events = events.is_a?(Array) ? events : [events]
|
51
|
-
_events.each do |event|
|
52
|
-
callbacks[[guard_class, event]] << listener
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def has_callback?(listener, guard_class, event)
|
57
|
-
callbacks[[guard_class, event]].include?(listener)
|
58
|
-
end
|
59
|
-
|
60
|
-
def notify(guard_class, event, *args)
|
61
|
-
callbacks[[guard_class, event]].each do |listener|
|
62
|
-
listener.call(guard_class, event, *args)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def reset_callbacks!
|
67
|
-
@callbacks = nil
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
end
|
1
|
+
module Guard
|
2
|
+
module Hook
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.send :include, InstanceMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module InstanceMethods
|
9
|
+
# When +event+ is a Symbol, #hook will generate a hook name
|
10
|
+
# by concatenating the method name from where #hook is called
|
11
|
+
# with the given Symbol.
|
12
|
+
# Example:
|
13
|
+
# def run_all
|
14
|
+
# hook :foo
|
15
|
+
# end
|
16
|
+
# Here, when #run_all is called, #hook will notify callbacks
|
17
|
+
# registered for the "run_all_foo" event.
|
18
|
+
#
|
19
|
+
# When +event+ is a String, #hook will directly turn the String
|
20
|
+
# into a Symbol.
|
21
|
+
# Example:
|
22
|
+
# def run_all
|
23
|
+
# hook "foo_bar"
|
24
|
+
# end
|
25
|
+
# Here, when #run_all is called, #hook will notify callbacks
|
26
|
+
# registered for the "foo_bar" event.
|
27
|
+
#
|
28
|
+
# +args+ parameter is passed as is to the callbacks registered
|
29
|
+
# for the given event.
|
30
|
+
def hook(event, *args)
|
31
|
+
hook_name = if event.is_a? Symbol
|
32
|
+
calling_method = caller[0][/`([^']*)'/, 1]
|
33
|
+
"#{calling_method}_#{event}"
|
34
|
+
else
|
35
|
+
event
|
36
|
+
end.to_sym
|
37
|
+
|
38
|
+
UI.debug "Hook :#{hook_name} executed for #{self.class}"
|
39
|
+
|
40
|
+
Hook.notify(self.class, hook_name, *args)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class << self
|
45
|
+
def callbacks
|
46
|
+
@callbacks ||= Hash.new { |hash, key| hash[key] = [] }
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_callback(listener, guard_class, events)
|
50
|
+
_events = events.is_a?(Array) ? events : [events]
|
51
|
+
_events.each do |event|
|
52
|
+
callbacks[[guard_class, event]] << listener
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def has_callback?(listener, guard_class, event)
|
57
|
+
callbacks[[guard_class, event]].include?(listener)
|
58
|
+
end
|
59
|
+
|
60
|
+
def notify(guard_class, event, *args)
|
61
|
+
callbacks[[guard_class, event]].each do |listener|
|
62
|
+
listener.call(guard_class, event, *args)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def reset_callbacks!
|
67
|
+
@callbacks = nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
data/lib/guard/interactor.rb
CHANGED
@@ -1,40 +1,40 @@
|
|
1
|
-
module Guard
|
2
|
-
class Interactor
|
3
|
-
|
4
|
-
attr_reader :locked
|
5
|
-
|
6
|
-
def initialize
|
7
|
-
@locked = false
|
8
|
-
end
|
9
|
-
|
10
|
-
def start
|
11
|
-
return if ENV["GUARD_ENV"] == 'test'
|
12
|
-
Thread.new do
|
13
|
-
loop do
|
14
|
-
if (entry = $stdin.gets) && !@locked
|
15
|
-
entry.gsub! /\n/, ''
|
16
|
-
case entry
|
17
|
-
when 'stop', 'quit', 'exit', 's', 'q', 'e'
|
18
|
-
::Guard.stop
|
19
|
-
when 'reload', 'r', 'z'
|
20
|
-
::Guard.reload
|
21
|
-
when 'pause', 'p'
|
22
|
-
::Guard.pause
|
23
|
-
else
|
24
|
-
::Guard.run_all
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def lock
|
32
|
-
@locked = true
|
33
|
-
end
|
34
|
-
|
35
|
-
def unlock
|
36
|
-
@locked = false
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
1
|
+
module Guard
|
2
|
+
class Interactor
|
3
|
+
|
4
|
+
attr_reader :locked
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@locked = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def start
|
11
|
+
return if ENV["GUARD_ENV"] == 'test'
|
12
|
+
Thread.new do
|
13
|
+
loop do
|
14
|
+
if (entry = $stdin.gets) && !@locked
|
15
|
+
entry.gsub! /\n/, ''
|
16
|
+
case entry
|
17
|
+
when 'stop', 'quit', 'exit', 's', 'q', 'e'
|
18
|
+
::Guard.stop
|
19
|
+
when 'reload', 'r', 'z'
|
20
|
+
::Guard.reload
|
21
|
+
when 'pause', 'p'
|
22
|
+
::Guard.pause
|
23
|
+
else
|
24
|
+
::Guard.run_all
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def lock
|
32
|
+
@locked = true
|
33
|
+
end
|
34
|
+
|
35
|
+
def unlock
|
36
|
+
@locked = false
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
data/lib/guard/listener.rb
CHANGED
@@ -1,191 +1,191 @@
|
|
1
|
-
require 'rbconfig'
|
2
|
-
require 'digest/sha1'
|
3
|
-
|
4
|
-
module Guard
|
5
|
-
|
6
|
-
autoload :Darwin, 'guard/listeners/darwin'
|
7
|
-
autoload :Linux, 'guard/listeners/linux'
|
8
|
-
autoload :Windows, 'guard/listeners/windows'
|
9
|
-
autoload :Polling, 'guard/listeners/polling'
|
10
|
-
|
11
|
-
class Listener
|
12
|
-
|
13
|
-
DefaultIgnorePaths = %w[. .. .bundle .git log tmp vendor]
|
14
|
-
attr_accessor :changed_files
|
15
|
-
attr_reader :directory, :ignore_paths, :locked
|
16
|
-
|
17
|
-
def self.select_and_init(*a)
|
18
|
-
if mac? && Darwin.usable?
|
19
|
-
Darwin.new(*a)
|
20
|
-
elsif linux? && Linux.usable?
|
21
|
-
Linux.new(*a)
|
22
|
-
elsif windows? && Windows.usable?
|
23
|
-
Windows.new(*a)
|
24
|
-
else
|
25
|
-
UI.info "Using polling (Please help us to support your system better than that.)"
|
26
|
-
Polling.new(*a)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def initialize(directory = Dir.pwd, options = {})
|
31
|
-
@directory = directory.to_s
|
32
|
-
@sha1_checksums_hash = {}
|
33
|
-
@relativize_paths = options.fetch(:relativize_paths, true)
|
34
|
-
@changed_files = []
|
35
|
-
@locked = false
|
36
|
-
@ignore_paths = DefaultIgnorePaths
|
37
|
-
@ignore_paths |= options[:ignore_paths] if options[:ignore_paths]
|
38
|
-
|
39
|
-
update_last_event
|
40
|
-
start_reactor
|
41
|
-
end
|
42
|
-
|
43
|
-
def start_reactor
|
44
|
-
return if ENV["GUARD_ENV"] == 'test'
|
45
|
-
Thread.new do
|
46
|
-
loop do
|
47
|
-
if @changed_files != [] && !@locked
|
48
|
-
changed_files = @changed_files.dup
|
49
|
-
clear_changed_files
|
50
|
-
::Guard.run_on_change(changed_files)
|
51
|
-
else
|
52
|
-
sleep 0.1
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def start
|
59
|
-
watch(@directory)
|
60
|
-
end
|
61
|
-
|
62
|
-
def stop
|
63
|
-
end
|
64
|
-
|
65
|
-
def lock
|
66
|
-
@locked = true
|
67
|
-
end
|
68
|
-
|
69
|
-
def unlock
|
70
|
-
@locked = false
|
71
|
-
end
|
72
|
-
|
73
|
-
def clear_changed_files
|
74
|
-
@changed_files.clear
|
75
|
-
end
|
76
|
-
|
77
|
-
def on_change(&callback)
|
78
|
-
@callback = callback
|
79
|
-
end
|
80
|
-
|
81
|
-
def update_last_event
|
82
|
-
@last_event = Time.now
|
83
|
-
end
|
84
|
-
|
85
|
-
def modified_files(dirs, options = {})
|
86
|
-
last_event = @last_event
|
87
|
-
update_last_event
|
88
|
-
files = potentially_modified_files(dirs, options).select { |path| file_modified?(path, last_event) }
|
89
|
-
relativize_paths(files)
|
90
|
-
end
|
91
|
-
|
92
|
-
def worker
|
93
|
-
raise NotImplementedError, "should respond to #watch"
|
94
|
-
end
|
95
|
-
|
96
|
-
# register a directory to watch. must be implemented by the subclasses
|
97
|
-
def watch(directory)
|
98
|
-
raise NotImplementedError, "do whatever you want here, given the directory as only argument"
|
99
|
-
end
|
100
|
-
|
101
|
-
def all_files
|
102
|
-
potentially_modified_files([@directory], :all => true)
|
103
|
-
end
|
104
|
-
|
105
|
-
# scopes all given paths to the current #directory
|
106
|
-
def relativize_paths(paths)
|
107
|
-
return paths unless relativize_paths?
|
108
|
-
paths.map do |path|
|
109
|
-
path.gsub(%r{^#{@directory}/}, '')
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def relativize_paths?
|
114
|
-
!!@relativize_paths
|
115
|
-
end
|
116
|
-
|
117
|
-
# return children of the passed dirs that are not in the ignore_paths list
|
118
|
-
def exclude_ignored_paths(dirs, ignore_paths = self.ignore_paths)
|
119
|
-
Dir.glob(dirs.map { |d| "#{d.sub(%r{/+$}, '')}/*" }, File::FNM_DOTMATCH).reject do |path|
|
120
|
-
ignore_paths.include?(File.basename(path))
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
private
|
125
|
-
|
126
|
-
def potentially_modified_files(dirs, options={})
|
127
|
-
paths = exclude_ignored_paths(dirs)
|
128
|
-
|
129
|
-
if options[:all]
|
130
|
-
paths.inject([]) do |array, path|
|
131
|
-
if File.file?(path)
|
132
|
-
array << path
|
133
|
-
else
|
134
|
-
array += Dir.glob("#{path}/**/*", File::FNM_DOTMATCH).select { |p| File.file?(p) }
|
135
|
-
end
|
136
|
-
array
|
137
|
-
end
|
138
|
-
else
|
139
|
-
paths.select { |path| File.file?(path) }
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
# Depending on the filesystem, mtime/ctime is probably only precise to the second, so round
|
144
|
-
# both values down to the second for the comparison.
|
145
|
-
# ctime is used only on == comparison to always catches Rails 3.1 Assets pipelined on Mac OSX
|
146
|
-
def file_modified?(path, last_event)
|
147
|
-
ctime = File.ctime(path).to_i
|
148
|
-
mtime = File.mtime(path).to_i
|
149
|
-
if [mtime, ctime].max == last_event.to_i
|
150
|
-
file_content_modified?(path, sha1_checksum(path))
|
151
|
-
elsif mtime > last_event.to_i
|
152
|
-
set_sha1_checksums_hash(path, sha1_checksum(path))
|
153
|
-
true
|
154
|
-
else
|
155
|
-
false
|
156
|
-
end
|
157
|
-
rescue
|
158
|
-
false
|
159
|
-
end
|
160
|
-
|
161
|
-
def file_content_modified?(path, sha1_checksum)
|
162
|
-
if @sha1_checksums_hash[path] != sha1_checksum
|
163
|
-
set_sha1_checksums_hash(path, sha1_checksum)
|
164
|
-
true
|
165
|
-
else
|
166
|
-
false
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def set_sha1_checksums_hash(path, sha1_checksum)
|
171
|
-
@sha1_checksums_hash[path] = sha1_checksum
|
172
|
-
end
|
173
|
-
|
174
|
-
def sha1_checksum(path)
|
175
|
-
Digest::SHA1.file(path).to_s
|
176
|
-
end
|
177
|
-
|
178
|
-
def self.mac?
|
179
|
-
RbConfig::CONFIG['target_os'] =~ /darwin/i
|
180
|
-
end
|
181
|
-
|
182
|
-
def self.linux?
|
183
|
-
RbConfig::CONFIG['target_os'] =~ /linux/i
|
184
|
-
end
|
185
|
-
|
186
|
-
def self.windows?
|
187
|
-
RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
|
188
|
-
end
|
189
|
-
|
190
|
-
end
|
191
|
-
end
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'digest/sha1'
|
3
|
+
|
4
|
+
module Guard
|
5
|
+
|
6
|
+
autoload :Darwin, 'guard/listeners/darwin'
|
7
|
+
autoload :Linux, 'guard/listeners/linux'
|
8
|
+
autoload :Windows, 'guard/listeners/windows'
|
9
|
+
autoload :Polling, 'guard/listeners/polling'
|
10
|
+
|
11
|
+
class Listener
|
12
|
+
|
13
|
+
DefaultIgnorePaths = %w[. .. .bundle .git log tmp vendor]
|
14
|
+
attr_accessor :changed_files
|
15
|
+
attr_reader :directory, :ignore_paths, :locked
|
16
|
+
|
17
|
+
def self.select_and_init(*a)
|
18
|
+
if mac? && Darwin.usable?
|
19
|
+
Darwin.new(*a)
|
20
|
+
elsif linux? && Linux.usable?
|
21
|
+
Linux.new(*a)
|
22
|
+
elsif windows? && Windows.usable?
|
23
|
+
Windows.new(*a)
|
24
|
+
else
|
25
|
+
UI.info "Using polling (Please help us to support your system better than that.)"
|
26
|
+
Polling.new(*a)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(directory = Dir.pwd, options = {})
|
31
|
+
@directory = directory.to_s
|
32
|
+
@sha1_checksums_hash = {}
|
33
|
+
@relativize_paths = options.fetch(:relativize_paths, true)
|
34
|
+
@changed_files = []
|
35
|
+
@locked = false
|
36
|
+
@ignore_paths = DefaultIgnorePaths
|
37
|
+
@ignore_paths |= options[:ignore_paths] if options[:ignore_paths]
|
38
|
+
|
39
|
+
update_last_event
|
40
|
+
start_reactor
|
41
|
+
end
|
42
|
+
|
43
|
+
def start_reactor
|
44
|
+
return if ENV["GUARD_ENV"] == 'test'
|
45
|
+
Thread.new do
|
46
|
+
loop do
|
47
|
+
if @changed_files != [] && !@locked
|
48
|
+
changed_files = @changed_files.dup
|
49
|
+
clear_changed_files
|
50
|
+
::Guard.run_on_change(changed_files)
|
51
|
+
else
|
52
|
+
sleep 0.1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def start
|
59
|
+
watch(@directory)
|
60
|
+
end
|
61
|
+
|
62
|
+
def stop
|
63
|
+
end
|
64
|
+
|
65
|
+
def lock
|
66
|
+
@locked = true
|
67
|
+
end
|
68
|
+
|
69
|
+
def unlock
|
70
|
+
@locked = false
|
71
|
+
end
|
72
|
+
|
73
|
+
def clear_changed_files
|
74
|
+
@changed_files.clear
|
75
|
+
end
|
76
|
+
|
77
|
+
def on_change(&callback)
|
78
|
+
@callback = callback
|
79
|
+
end
|
80
|
+
|
81
|
+
def update_last_event
|
82
|
+
@last_event = Time.now
|
83
|
+
end
|
84
|
+
|
85
|
+
def modified_files(dirs, options = {})
|
86
|
+
last_event = @last_event
|
87
|
+
update_last_event
|
88
|
+
files = potentially_modified_files(dirs, options).select { |path| file_modified?(path, last_event) }
|
89
|
+
relativize_paths(files)
|
90
|
+
end
|
91
|
+
|
92
|
+
def worker
|
93
|
+
raise NotImplementedError, "should respond to #watch"
|
94
|
+
end
|
95
|
+
|
96
|
+
# register a directory to watch. must be implemented by the subclasses
|
97
|
+
def watch(directory)
|
98
|
+
raise NotImplementedError, "do whatever you want here, given the directory as only argument"
|
99
|
+
end
|
100
|
+
|
101
|
+
def all_files
|
102
|
+
potentially_modified_files([@directory], :all => true)
|
103
|
+
end
|
104
|
+
|
105
|
+
# scopes all given paths to the current #directory
|
106
|
+
def relativize_paths(paths)
|
107
|
+
return paths unless relativize_paths?
|
108
|
+
paths.map do |path|
|
109
|
+
path.gsub(%r{^#{@directory}/}, '')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def relativize_paths?
|
114
|
+
!!@relativize_paths
|
115
|
+
end
|
116
|
+
|
117
|
+
# return children of the passed dirs that are not in the ignore_paths list
|
118
|
+
def exclude_ignored_paths(dirs, ignore_paths = self.ignore_paths)
|
119
|
+
Dir.glob(dirs.map { |d| "#{d.sub(%r{/+$}, '')}/*" }, File::FNM_DOTMATCH).reject do |path|
|
120
|
+
ignore_paths.include?(File.basename(path))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def potentially_modified_files(dirs, options={})
|
127
|
+
paths = exclude_ignored_paths(dirs)
|
128
|
+
|
129
|
+
if options[:all]
|
130
|
+
paths.inject([]) do |array, path|
|
131
|
+
if File.file?(path)
|
132
|
+
array << path
|
133
|
+
else
|
134
|
+
array += Dir.glob("#{path}/**/*", File::FNM_DOTMATCH).select { |p| File.file?(p) }
|
135
|
+
end
|
136
|
+
array
|
137
|
+
end
|
138
|
+
else
|
139
|
+
paths.select { |path| File.file?(path) }
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Depending on the filesystem, mtime/ctime is probably only precise to the second, so round
|
144
|
+
# both values down to the second for the comparison.
|
145
|
+
# ctime is used only on == comparison to always catches Rails 3.1 Assets pipelined on Mac OSX
|
146
|
+
def file_modified?(path, last_event)
|
147
|
+
ctime = File.ctime(path).to_i
|
148
|
+
mtime = File.mtime(path).to_i
|
149
|
+
if [mtime, ctime].max == last_event.to_i
|
150
|
+
file_content_modified?(path, sha1_checksum(path))
|
151
|
+
elsif mtime > last_event.to_i
|
152
|
+
set_sha1_checksums_hash(path, sha1_checksum(path))
|
153
|
+
true
|
154
|
+
else
|
155
|
+
false
|
156
|
+
end
|
157
|
+
rescue
|
158
|
+
false
|
159
|
+
end
|
160
|
+
|
161
|
+
def file_content_modified?(path, sha1_checksum)
|
162
|
+
if @sha1_checksums_hash[path] != sha1_checksum
|
163
|
+
set_sha1_checksums_hash(path, sha1_checksum)
|
164
|
+
true
|
165
|
+
else
|
166
|
+
false
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def set_sha1_checksums_hash(path, sha1_checksum)
|
171
|
+
@sha1_checksums_hash[path] = sha1_checksum
|
172
|
+
end
|
173
|
+
|
174
|
+
def sha1_checksum(path)
|
175
|
+
Digest::SHA1.file(path).to_s
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.mac?
|
179
|
+
RbConfig::CONFIG['target_os'] =~ /darwin/i
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.linux?
|
183
|
+
RbConfig::CONFIG['target_os'] =~ /linux/i
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.windows?
|
187
|
+
RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
end
|