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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e35654286f32140f640677be45768252c787b496
4
- data.tar.gz: 7edf8aa92f327d5ba8e96c25a8731b249b05f6e0
3
+ metadata.gz: 2e83395d241b8365a554f4f56d3c6a79019e4912
4
+ data.tar.gz: 02c1657d7907c8a9955b1d329cb343cd5946a1af
5
5
  SHA512:
6
- metadata.gz: 8c06e927233aed011f491da416cec580053dda563f9dcbce6777c341f03a290a1e7db064a9a86c91c42f51034fc9a1c10b4e85dc85f5eb619f8d05a120221653
7
- data.tar.gz: 54b64d67398fb465a1a679f91b9d381a8bbce41044e66514b7c20b9cd89ae32da0bf4c060ba8daa10ce0cf68f78d6f55de95750941860f5fd63832def8a90e55
6
+ metadata.gz: ce8ea60d34378a7bd007479e5ec7b005819d5484421adfc14bae08331eca00b5e62c6eee56ad8828d8547b4c06339c9d644ff46f94e0f77fd481e664b354cdf3
7
+ data.tar.gz: 84980ca0c4bfc21caf219355276ff44463c665b0d0e4802603d92a583ba9288513a03e9bc3877e1d6b9e2a2bd86799e8c3d5405019e2326e6324e91340ca8824
@@ -146,6 +146,12 @@ module Build
146
146
 
147
147
  attr :files
148
148
 
149
+ def freeze
150
+ self.roots
151
+
152
+ super
153
+ end
154
+
149
155
  def each
150
156
  return to_enum(:each) unless block_given?
151
157
 
@@ -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
- directories.each do |directory|
39
- # directory = File.realpath(directory)
40
-
41
- @directories[directory].each do |handle|
42
- handle.changed!(*args)
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
- # Remove the entire record if there are no handles:
56
- if @directories[directory].size == 0
57
- @directories.delete(directory)
58
-
59
- @updated = true
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
@@ -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
- class State
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
- @files.to_a.empty?
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
- attr :input_state
147
- attr :output_state
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
- # Output is dirty if files are missing or if latest input is older than any output.
150
- def dirty?
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 as long as outputs exist:
160
- # if @input_state.empty?
161
- # return false
162
- # end
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 = @output_state.oldest_time
165
- newest_input_time = @input_state.newest_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 newest_input_time > oldest_output_time
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
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Build
22
22
  module Files
23
- VERSION = "0.3.1"
23
+ VERSION = "0.3.2"
24
24
  end
25
25
  end
@@ -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.1
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-18 00:00:00.000000000 Z
11
+ date: 2015-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler