build-files 0.3.1 → 0.3.2
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.
- checksums.yaml +4 -4
- data/lib/build/files/list.rb +6 -0
- data/lib/build/files/monitor.rb +74 -22
- data/lib/build/files/state.rb +33 -104
- data/lib/build/files/version.rb +1 -1
- data/spec/build/files/state_spec.rb +8 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e83395d241b8365a554f4f56d3c6a79019e4912
|
4
|
+
data.tar.gz: 02c1657d7907c8a9955b1d329cb343cd5946a1af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce8ea60d34378a7bd007479e5ec7b005819d5484421adfc14bae08331eca00b5e62c6eee56ad8828d8547b4c06339c9d644ff46f94e0f77fd481e664b354cdf3
|
7
|
+
data.tar.gz: 84980ca0c4bfc21caf219355276ff44463c665b0d0e4802603d92a583ba9288513a03e9bc3877e1d6b9e2a2bd86799e8c3d5405019e2326e6324e91340ca8824
|
data/lib/build/files/list.rb
CHANGED
data/lib/build/files/monitor.rb
CHANGED
@@ -24,60 +24,85 @@ require 'build/files/state'
|
|
24
24
|
|
25
25
|
module Build
|
26
26
|
module Files
|
27
|
+
class Handle
|
28
|
+
def initialize(monitor, files, &block)
|
29
|
+
@monitor = monitor
|
30
|
+
@state = State.new(files)
|
31
|
+
@on_changed = block
|
32
|
+
end
|
33
|
+
|
34
|
+
attr :monitor
|
35
|
+
|
36
|
+
def commit!
|
37
|
+
@state.update!
|
38
|
+
end
|
39
|
+
|
40
|
+
def directories
|
41
|
+
@state.files.roots
|
42
|
+
end
|
43
|
+
|
44
|
+
def remove!
|
45
|
+
monitor.delete(self)
|
46
|
+
end
|
47
|
+
|
48
|
+
def changed!
|
49
|
+
@on_changed.call(@state) if @state.update!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
27
53
|
class Monitor
|
28
54
|
def initialize
|
29
55
|
@directories = Hash.new { |hash, key| hash[key] = Set.new }
|
30
56
|
|
31
57
|
@updated = false
|
58
|
+
|
59
|
+
@deletions = nil
|
32
60
|
end
|
33
61
|
|
34
62
|
attr :updated
|
35
63
|
|
36
64
|
# Notify the monitor that files in these directories have changed.
|
37
65
|
def update(directories, *args)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
handle
|
66
|
+
delay_deletions do
|
67
|
+
directories.each do |directory|
|
68
|
+
# directory = File.realpath(directory)
|
69
|
+
|
70
|
+
@directories[directory].each do |handle|
|
71
|
+
handle.changed!(*args)
|
72
|
+
end
|
43
73
|
end
|
44
74
|
end
|
45
75
|
end
|
46
|
-
|
76
|
+
|
47
77
|
def roots
|
48
78
|
@directories.keys
|
49
79
|
end
|
50
|
-
|
51
|
-
def delete(handle)
|
52
|
-
handle.directories.each do |directory|
|
53
|
-
@directories[directory].delete(handle)
|
54
80
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
81
|
+
def delete(handle)
|
82
|
+
if @deletions
|
83
|
+
@deletions << handle
|
84
|
+
else
|
85
|
+
purge(handle)
|
61
86
|
end
|
62
87
|
end
|
63
|
-
|
88
|
+
|
64
89
|
def track_changes(files, &block)
|
65
90
|
handle = Handle.new(self, files, &block)
|
66
|
-
|
91
|
+
|
67
92
|
add(handle)
|
68
93
|
end
|
69
|
-
|
94
|
+
|
70
95
|
def add(handle)
|
71
96
|
handle.directories.each do |directory|
|
72
97
|
@directories[directory] << handle
|
73
|
-
|
98
|
+
|
74
99
|
# We just added the first handle:
|
75
100
|
if @directories[directory].size == 1
|
76
101
|
# If the handle already existed, this might trigger unnecessarily.
|
77
102
|
@updated = true
|
78
103
|
end
|
79
104
|
end
|
80
|
-
|
105
|
+
|
81
106
|
handle
|
82
107
|
end
|
83
108
|
|
@@ -93,6 +118,33 @@ module Build
|
|
93
118
|
Files.send(method_name, self, options, &block)
|
94
119
|
end
|
95
120
|
end
|
121
|
+
|
122
|
+
protected
|
123
|
+
|
124
|
+
def delay_deletions
|
125
|
+
@deletions = []
|
126
|
+
|
127
|
+
yield
|
128
|
+
|
129
|
+
@deletions.each do |handle|
|
130
|
+
purge(handle)
|
131
|
+
end
|
132
|
+
|
133
|
+
@deletions = nil
|
134
|
+
end
|
135
|
+
|
136
|
+
def purge(handle)
|
137
|
+
handle.directories.each do |directory|
|
138
|
+
@directories[directory].delete(handle)
|
139
|
+
|
140
|
+
# Remove the entire record if there are no handles:
|
141
|
+
if @directories[directory].size == 0
|
142
|
+
@directories.delete(directory)
|
143
|
+
|
144
|
+
@updated = true
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
96
148
|
end
|
97
149
|
|
98
150
|
def self.run_with_inotify(monitor, options = {}, &block)
|
@@ -135,7 +187,7 @@ module Build
|
|
135
187
|
notifier.stop
|
136
188
|
end
|
137
189
|
end
|
138
|
-
|
190
|
+
|
139
191
|
notifier.run
|
140
192
|
end
|
141
193
|
end
|
data/lib/build/files/state.rb
CHANGED
@@ -18,6 +18,10 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
+
require_relative 'list'
|
22
|
+
|
23
|
+
require 'forwardable'
|
24
|
+
|
21
25
|
module Build
|
22
26
|
module Files
|
23
27
|
# Represents a specific file on disk with a specific mtime.
|
@@ -41,35 +45,40 @@ module Build
|
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
44
|
-
|
48
|
+
# A stateful list of files captured at a specific time, which can then be checked for changes.
|
49
|
+
class State < Files::List
|
50
|
+
extend Forwardable
|
51
|
+
|
45
52
|
def initialize(files)
|
46
53
|
raise ArgumentError.new("Invalid files list: #{files}") unless Files::List === files
|
47
|
-
|
54
|
+
|
48
55
|
@files = files
|
49
|
-
|
56
|
+
|
50
57
|
@times = {}
|
51
|
-
|
58
|
+
|
52
59
|
update!
|
53
60
|
end
|
54
|
-
|
61
|
+
|
55
62
|
attr :files
|
56
|
-
|
63
|
+
|
57
64
|
attr :added
|
58
65
|
attr :removed
|
59
66
|
attr :changed
|
60
67
|
attr :missing
|
61
|
-
|
68
|
+
|
62
69
|
attr :times
|
63
|
-
|
70
|
+
|
71
|
+
def_delegators :@files, :each, :roots, :count
|
72
|
+
|
64
73
|
def update!
|
65
74
|
last_times = @times
|
66
75
|
@times = {}
|
67
|
-
|
76
|
+
|
68
77
|
@added = []
|
69
78
|
@removed = []
|
70
79
|
@changed = []
|
71
80
|
@missing = []
|
72
|
-
|
81
|
+
|
73
82
|
file_times = []
|
74
83
|
|
75
84
|
@files.each do |path|
|
@@ -123,120 +132,40 @@ module Build
|
|
123
132
|
!@missing.empty?
|
124
133
|
end
|
125
134
|
|
126
|
-
# Outputs is a list of full paths and must not include any patterns/globs.
|
127
|
-
def intersects?(outputs)
|
128
|
-
@files.intersects?(outputs)
|
129
|
-
end
|
130
|
-
|
131
135
|
def empty?
|
132
|
-
@
|
136
|
+
@times.empty?
|
133
137
|
end
|
134
138
|
|
135
139
|
def inspect
|
136
140
|
"<State Added:#{@added} Removed:#{@removed} Changed:#{@changed} Missing:#{@missing}>"
|
137
141
|
end
|
138
|
-
end
|
139
|
-
|
140
|
-
class IOState
|
141
|
-
def initialize(inputs, outputs)
|
142
|
-
@input_state = State.new(inputs)
|
143
|
-
@output_state = State.new(outputs)
|
144
|
-
end
|
145
142
|
|
146
|
-
|
147
|
-
|
143
|
+
# Are these files dirty with respect to the given inputs?
|
144
|
+
def dirty?(inputs)
|
145
|
+
self.class.dirty?(inputs, self)
|
146
|
+
end
|
148
147
|
|
149
|
-
|
150
|
-
|
151
|
-
@dirty = []
|
152
|
-
|
153
|
-
if @output_state.missing?
|
148
|
+
def self.dirty?(inputs, outputs)
|
149
|
+
if outputs.missing?
|
154
150
|
# puts "Output file missing: #{output_state.missing.inspect}"
|
155
|
-
|
156
151
|
return true
|
157
152
|
end
|
158
153
|
|
159
|
-
# If there are no inputs, we are always clean
|
160
|
-
|
161
|
-
|
162
|
-
|
154
|
+
# If there are no inputs or no outputs, we are always clean:
|
155
|
+
if inputs.empty? or outputs.empty?
|
156
|
+
return false
|
157
|
+
end
|
163
158
|
|
164
|
-
oldest_output_time =
|
165
|
-
newest_input_time =
|
159
|
+
oldest_output_time = outputs.oldest_time
|
160
|
+
newest_input_time = inputs.newest_time
|
166
161
|
|
167
162
|
if newest_input_time and oldest_output_time
|
168
|
-
# if
|
169
|
-
# puts "Out of date file: #{newest_input_time.inspect} > #{oldest_output_time.inspect}"
|
170
|
-
# end
|
171
|
-
|
163
|
+
# We are dirty if any inputs are newer (bigger) than any outputs:
|
172
164
|
return newest_input_time > oldest_output_time
|
173
165
|
end
|
174
166
|
|
175
|
-
# puts "Missing file dates: #{newest_input_time.inspect} < #{oldest_output_time.inspect}"
|
176
|
-
|
177
167
|
return true
|
178
168
|
end
|
179
|
-
|
180
|
-
def fresh?
|
181
|
-
not dirty?
|
182
|
-
end
|
183
|
-
|
184
|
-
def files
|
185
|
-
@input_state.files + @output_state.files
|
186
|
-
end
|
187
|
-
|
188
|
-
def added
|
189
|
-
@input_state.added + @output_state.added
|
190
|
-
end
|
191
|
-
|
192
|
-
def removed
|
193
|
-
@input_state.removed + @output_state.removed
|
194
|
-
end
|
195
|
-
|
196
|
-
def changed
|
197
|
-
@input_state.changed + @output_state.changed
|
198
|
-
end
|
199
|
-
|
200
|
-
def update!
|
201
|
-
input_changed = @input_state.update!
|
202
|
-
output_changed = @output_state.update!
|
203
|
-
|
204
|
-
input_changed or output_changed
|
205
|
-
end
|
206
|
-
|
207
|
-
def intersects?(outputs)
|
208
|
-
@input_state.intersects?(outputs) or @output_state.intersects?(outputs)
|
209
|
-
end
|
210
|
-
|
211
|
-
def inspect
|
212
|
-
"<IOState Input:#{@input_state.inspect} Output:#{@output_state.inspect}>"
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
class Handle
|
217
|
-
def initialize(monitor, files, &block)
|
218
|
-
@monitor = monitor
|
219
|
-
@state = State.new(files)
|
220
|
-
@on_changed = block
|
221
|
-
end
|
222
|
-
|
223
|
-
attr :monitor
|
224
|
-
|
225
|
-
def commit!
|
226
|
-
@state.update!
|
227
|
-
end
|
228
|
-
|
229
|
-
def directories
|
230
|
-
@state.files.roots
|
231
|
-
end
|
232
|
-
|
233
|
-
def remove!
|
234
|
-
monitor.delete(self)
|
235
|
-
end
|
236
|
-
|
237
|
-
def changed!
|
238
|
-
@on_changed.call(@state) if @state.update!
|
239
|
-
end
|
240
169
|
end
|
241
170
|
end
|
242
171
|
end
|
data/lib/build/files/version.rb
CHANGED
@@ -56,5 +56,13 @@ module Build::Files::StateSpec
|
|
56
56
|
expect(state.removed).to be == []
|
57
57
|
expect(state.missing).to be == []
|
58
58
|
end
|
59
|
+
|
60
|
+
it "should be clean with empty inputs or outputs" do
|
61
|
+
empty = Build::Files::State.new(Build::Files::Paths::NONE)
|
62
|
+
something = Build::Files::State.new(files)
|
63
|
+
|
64
|
+
expect(Build::Files::State.dirty?(empty, something)).to be false
|
65
|
+
expect(Build::Files::State.dirty?(something, empty)).to be false
|
66
|
+
end
|
59
67
|
end
|
60
68
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: build-files
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|