build-files 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b77938366786dd5d7f79073be6f1315a32c0660a5e3d7979614c4f0f79a67ebc
4
- data.tar.gz: 0f475f88831d52d006e77fc9a9edb291cfee7e6692450d4d450e5fba2b58057b
3
+ metadata.gz: 266f5c2f5a839934620afe4a06289bf7c4363d39c04b39fc3fef8b87104d7ff1
4
+ data.tar.gz: b775a997766d4ff2fc751e08fc93d6512a373e944813ee09097731f432087714
5
5
  SHA512:
6
- metadata.gz: 57e65db4d252786a52573129c305e82a98833ed89adcb06e50c88c36cf8f504d66de8cae63d0f656fb6e770742f87e344805c701d734bba305a68a4380f84590
7
- data.tar.gz: dd50577d7386bd2ce60158e1321bc25dd5fea5d3e80fc26b5ede43f0c2e1faceac4b55ec98eb40b9791a6d1037726bc6c2bd44b63441368011ca10a154283241
6
+ metadata.gz: 303be1f16bcadc201db4fd2c9530250926942e1f3f63d269646d943ca439b2c2ca930c0a9fc5caeb16fc4c35362c84580699f5732917f9df51739f339aa7640c
7
+ data.tar.gz: 52f6d5d1441dcd15d5be335cab08620aa41524aef8294a13c4adaa2df5513d9e1a03b29b42336afe29b98bdd6f8f1c53c1eb90d7279d855738acfe4e0a29be3b
data/build-files.gemspec CHANGED
@@ -18,9 +18,6 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.required_ruby_version = '>= 2.0'
20
20
 
21
- spec.add_dependency "rb-inotify"
22
- spec.add_dependency "rb-fsevent"
23
-
24
21
  spec.add_development_dependency "covered"
25
22
  spec.add_development_dependency "bundler"
26
23
  spec.add_development_dependency "rspec", "~> 3.4"
data/lib/build/files.rb CHANGED
@@ -24,7 +24,4 @@ require_relative 'files/paths'
24
24
  require_relative 'files/glob'
25
25
  require_relative 'files/directory'
26
26
 
27
- require_relative 'files/state'
28
- require_relative 'files/monitor'
29
-
30
27
  require_relative 'files/system'
@@ -22,6 +22,10 @@ module Build
22
22
  module Files
23
23
  # Represents a file path with an absolute root and a relative offset:
24
24
  class Path
25
+ def self.current
26
+ self.new(::Dir.pwd)
27
+ end
28
+
25
29
  def self.split(path)
26
30
  # Effectively dirname and basename:
27
31
  dirname, separator, filename = path.rpartition(File::SEPARATOR)
@@ -44,6 +48,14 @@ module Build
44
48
  end
45
49
  end
46
50
 
51
+ def self.root(path)
52
+ if Path === path
53
+ path.root
54
+ else
55
+ File.dirname(path)
56
+ end
57
+ end
58
+
47
59
  # Return the shortest relative path to get to path from root. Root should be a directory with which you are computing the relative path.
48
60
  def self.shortest_path(path, root)
49
61
  path_components = Path.components(path)
@@ -106,6 +118,17 @@ module Build
106
118
  self.parts.last
107
119
  end
108
120
 
121
+ def parent
122
+ root = @root
123
+ full_path = File.dirname(@full_path)
124
+
125
+ while root.size > full_path.size
126
+ root = Path.root(root)
127
+ end
128
+
129
+ self.class.new(full_path, root)
130
+ end
131
+
109
132
  def start_with?(*args)
110
133
  @full_path.start_with?(*args)
111
134
  end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Build
22
22
  module Files
23
- VERSION = "1.6.0"
23
+ VERSION = "1.7.0"
24
24
  end
25
25
  end
@@ -24,6 +24,10 @@ require 'build/files/path'
24
24
  require 'pathname'
25
25
 
26
26
  RSpec.describe Build::Files::Path do
27
+ it "can get current path" do
28
+ expect(Build::Files::Path.current.full_path).to be == Dir.pwd
29
+ end
30
+
27
31
  it "should expand the path" do
28
32
  expect(Build::Files::Path.expand("foo", "/bar")).to be == "/bar/foo"
29
33
  end
@@ -88,6 +92,14 @@ RSpec.describe Build::Files::Path.new("/foo/bar.txt") do
88
92
  end
89
93
 
90
94
  RSpec.describe Build::Files::Path.new("/foo/bar/baz", "/foo") do
95
+ it "can compute parent path" do
96
+ parent = subject.parent
97
+
98
+ expect(parent.root).to be == subject.root
99
+ expect(parent.relative_path).to be == "bar"
100
+ expect(parent.full_path).to be == "/foo/bar"
101
+ end
102
+
91
103
  it "can add nil path" do
92
104
  expect(subject + nil).to be == subject
93
105
  end
metadata CHANGED
@@ -1,43 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: build-files
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-12 00:00:00.000000000 Z
11
+ date: 2021-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: rb-inotify
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: rb-fsevent
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
13
  - !ruby/object:Gem::Dependency
42
14
  name: covered
43
15
  requirement: !ruby/object:Gem::Requirement
@@ -94,7 +66,7 @@ dependencies:
94
66
  - - ">="
95
67
  - !ruby/object:Gem::Version
96
68
  version: '0'
97
- description:
69
+ description:
98
70
  email:
99
71
  - samuel.williams@oriontransfer.co.nz
100
72
  executables: []
@@ -112,15 +84,9 @@ files:
112
84
  - lib/build/files/difference.rb
113
85
  - lib/build/files/directory.rb
114
86
  - lib/build/files/glob.rb
115
- - lib/build/files/handle.rb
116
87
  - lib/build/files/list.rb
117
- - lib/build/files/monitor.rb
118
- - lib/build/files/monitor/fsevent.rb
119
- - lib/build/files/monitor/inotify.rb
120
- - lib/build/files/monitor/polling.rb
121
88
  - lib/build/files/path.rb
122
89
  - lib/build/files/paths.rb
123
- - lib/build/files/state.rb
124
90
  - lib/build/files/system.rb
125
91
  - lib/build/files/version.rb
126
92
  - spec/build/files/directory_spec.rb
@@ -129,16 +95,14 @@ files:
129
95
  - spec/build/files/glob_spec.rb
130
96
  - spec/build/files/glob_spec/dotfiles/.file
131
97
  - spec/build/files/list_spec.rb
132
- - spec/build/files/monitor_spec.rb
133
98
  - spec/build/files/path_spec.rb
134
- - spec/build/files/state_spec.rb
135
99
  - spec/build/files/system_spec.rb
136
100
  - spec/spec_helper.rb
137
101
  homepage: ''
138
102
  licenses:
139
103
  - MIT
140
104
  metadata: {}
141
- post_install_message:
105
+ post_install_message:
142
106
  rdoc_options: []
143
107
  require_paths:
144
108
  - lib
@@ -153,8 +117,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
117
  - !ruby/object:Gem::Version
154
118
  version: '0'
155
119
  requirements: []
156
- rubygems_version: 3.1.2
157
- signing_key:
120
+ rubygems_version: 3.2.3
121
+ signing_key:
158
122
  specification_version: 4
159
123
  summary: Build::Files is a set of idiomatic classes for dealing with paths and monitoring
160
124
  directories.
@@ -165,8 +129,6 @@ test_files:
165
129
  - spec/build/files/glob_spec.rb
166
130
  - spec/build/files/glob_spec/dotfiles/.file
167
131
  - spec/build/files/list_spec.rb
168
- - spec/build/files/monitor_spec.rb
169
132
  - spec/build/files/path_spec.rb
170
- - spec/build/files/state_spec.rb
171
133
  - spec/build/files/system_spec.rb
172
134
  - spec/spec_helper.rb
@@ -1,59 +0,0 @@
1
- # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require_relative 'state'
22
-
23
- module Build
24
- module Files
25
- class Handle
26
- def initialize(monitor, files, &block)
27
- @monitor = monitor
28
- @state = State.new(files)
29
- @block = block
30
- end
31
-
32
- attr :monitor
33
-
34
- def commit!
35
- @state.update!
36
- end
37
-
38
- def directories
39
- @state.files.roots
40
- end
41
-
42
- def remove!
43
- @monitor.delete(self)
44
- end
45
-
46
- # Inform the handle that it might have been modified.
47
- def changed!
48
- # If @state.update! did not find any changes, don't invoke the callback:
49
- if @state.update!
50
- @block.call(@state)
51
- end
52
- end
53
-
54
- def to_s
55
- "\#<#{self.class} @state=#{@state} @block=#{@block}>"
56
- end
57
- end
58
- end
59
- end
@@ -1,43 +0,0 @@
1
- # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- module Build
22
- module Files
23
- module Monitor
24
- case RUBY_PLATFORM
25
- when /linux/i
26
- require_relative 'monitor/inotify'
27
- Native = INotify
28
- Default = Native
29
- when /darwin/i
30
- require_relative 'monitor/fsevent'
31
- Native = FSEvent
32
- Default = Native
33
- else
34
- require_relative 'monitor/polling'
35
- Default = Polling
36
- end
37
-
38
- def self.new(*args)
39
- Default.new(*args)
40
- end
41
- end
42
- end
43
- end
@@ -1,55 +0,0 @@
1
- # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require_relative 'polling'
22
-
23
- require 'rb-fsevent'
24
-
25
- module Build
26
- module Files
27
- module Monitor
28
- class FSEvent < Polling
29
- def run(**options, &block)
30
- notifier = ::FSEvent.new
31
-
32
- catch(:interrupt) do
33
- while true
34
- notifier.watch self.roots do |directories|
35
- directories.collect! do |directory|
36
- File.expand_path(directory)
37
- end
38
-
39
- self.update(directories)
40
-
41
- yield
42
-
43
- if self.updated
44
- notifier.stop
45
- end
46
- end
47
-
48
- notifier.run
49
- end
50
- end
51
- end
52
- end
53
- end
54
- end
55
- end
@@ -1,53 +0,0 @@
1
- # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require_relative 'polling'
22
-
23
- require 'rb-inotify'
24
-
25
- module Build
26
- module Files
27
- module Monitor
28
- class INotify < Polling
29
- def run(**options, &block)
30
- notifier = ::INotify::Notifier.new
31
-
32
- catch(:interrupt) do
33
- while true
34
- self.roots.each do |root|
35
- notifier.watch root, :create, :modify, :attrib, :delete do |event|
36
- self.update([root])
37
-
38
- yield
39
-
40
- if self.updated
41
- notifier.stop
42
- end
43
- end
44
- end
45
-
46
- notifier.run
47
- end
48
- end
49
- end
50
- end
51
- end
52
- end
53
- end
@@ -1,145 +0,0 @@
1
- # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require 'set'
22
- require 'logger'
23
-
24
- require_relative '../handle'
25
-
26
- module Build
27
- module Files
28
- module Monitor
29
- class Polling
30
- def initialize(logger: nil)
31
- @directories = Hash.new do |hash, key|
32
- hash[key] = Set.new
33
- end
34
-
35
- @updated = false
36
-
37
- @deletions = nil
38
-
39
- @logger = logger || Logger.new(nil)
40
- end
41
-
42
- attr :updated
43
-
44
- # Notify the monitor that files in these directories have changed.
45
- def update(directories, *args)
46
- @logger.debug{"Update: #{directories} #{args.inspect}"}
47
-
48
- delay_deletions do
49
- directories.each do |directory|
50
- @logger.debug{"Directory: #{directory}"}
51
-
52
- @directories[directory].each do |handle|
53
- @logger.debug{"Handle changed: #{handle.inspect}"}
54
-
55
- # Changes here may not actually require an update to the handle:
56
- handle.changed!(*args)
57
- end
58
- end
59
- end
60
- end
61
-
62
- def roots
63
- @directories.keys
64
- end
65
-
66
- def delete(handle)
67
- if @deletions
68
- @logger.debug{"Delayed delete handle: #{handle}"}
69
- @deletions << handle
70
- else
71
- purge(handle)
72
- end
73
- end
74
-
75
- def track_changes(files, &block)
76
- handle = Handle.new(self, files, &block)
77
-
78
- add(handle)
79
- end
80
-
81
- def add(handle)
82
- @logger.debug{"Adding handle: #{handle}"}
83
-
84
- handle.directories.each do |directory|
85
- # We want the full path as a plain string:
86
- directory = directory.to_s
87
-
88
- @directories[directory] << handle
89
-
90
- # We just added the first handle:
91
- if @directories[directory].size == 1
92
- # If the handle already existed, this might trigger unnecessarily.
93
- @updated = true
94
- end
95
- end
96
-
97
- handle
98
- end
99
-
100
- def run(**options, &block)
101
- catch(:interrupt) do
102
- while true
103
- monitor.update(monitor.roots)
104
-
105
- yield
106
-
107
- sleep(options[:latency] || 1.0)
108
- end
109
- end
110
- end
111
-
112
- protected
113
-
114
- def delay_deletions
115
- @deletions = []
116
-
117
- yield
118
-
119
- @deletions.each do |handle|
120
- purge(handle)
121
- end
122
-
123
- @deletions = nil
124
- end
125
-
126
- def purge(handle)
127
- @logger.debug{"Purge handle: #{handle}"}
128
-
129
- handle.directories.each do |directory|
130
- directory = directory.to_s
131
-
132
- @directories[directory].delete(handle)
133
-
134
- # Remove the entire record if there are no handles:
135
- if @directories[directory].size == 0
136
- @directories.delete(directory)
137
-
138
- @updated = true
139
- end
140
- end
141
- end
142
- end
143
- end
144
- end
145
- end
@@ -1,172 +0,0 @@
1
- # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require_relative 'list'
22
-
23
- require 'forwardable'
24
-
25
- module Build
26
- module Files
27
- # Represents a specific file on disk with a specific mtime.
28
- class FileTime
29
- include Comparable
30
-
31
- def initialize(path, time)
32
- @path = path
33
- @time = time
34
- end
35
-
36
- attr :path
37
- attr :time
38
-
39
- def <=> other
40
- @time <=> other.time
41
- end
42
-
43
- def inspect
44
- "<FileTime #{@path.inspect} #{@time.inspect}>"
45
- end
46
- end
47
-
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
-
52
- def initialize(files)
53
- raise ArgumentError.new("Invalid files list: #{files}") unless Files::List === files
54
-
55
- @files = files
56
-
57
- @times = {}
58
-
59
- update!
60
- end
61
-
62
- attr :files
63
-
64
- attr :added
65
- attr :removed
66
- attr :changed
67
- attr :missing
68
-
69
- attr :times
70
-
71
- def_delegators :@files, :each, :roots, :count
72
-
73
- def update!
74
- last_times = @times
75
- @times = {}
76
-
77
- @added = []
78
- @removed = []
79
- @changed = []
80
- @missing = []
81
-
82
- file_times = []
83
-
84
- @files.each do |path|
85
- # When processing the same path twice (perhaps by accident), we should skip it otherwise it might cause issues when being deleted from last_times multuple times.
86
- next if @times.include? path
87
-
88
- if File.exist?(path)
89
- modified_time = File.mtime(path)
90
-
91
- if last_time = last_times.delete(path)
92
- # Path was valid last update:
93
- if modified_time != last_time
94
- @changed << path
95
-
96
- # puts "Changed: #{path}"
97
- end
98
- else
99
- # Path didn't exist before:
100
- @added << path
101
-
102
- # puts "Added: #{path}"
103
- end
104
-
105
- @times[path] = modified_time
106
-
107
- unless File.directory?(path)
108
- file_times << FileTime.new(path, modified_time)
109
- end
110
- else
111
- @missing << path
112
-
113
- # puts "Missing: #{path}"
114
- end
115
- end
116
-
117
- @removed = last_times.keys
118
- # puts "Removed: #{@removed.inspect}" if @removed.size > 0
119
-
120
- @oldest_time = file_times.min
121
- @newest_time = file_times.max
122
-
123
- return @added.size > 0 || @changed.size > 0 || @removed.size > 0 || @missing.size > 0
124
- end
125
-
126
- attr :oldest_time
127
- attr :newest_time
128
-
129
- def missing?
130
- !@missing.empty?
131
- end
132
-
133
- def empty?
134
- @times.empty?
135
- end
136
-
137
- def inspect
138
- "<State Added:#{@added} Removed:#{@removed} Changed:#{@changed} Missing:#{@missing}>"
139
- end
140
-
141
- # Are these (output) files dirty with respect to the given inputs?
142
- def dirty?(inputs)
143
- if self.missing?
144
- return true
145
- end
146
-
147
- # If there are no inputs or no outputs, we are always clean:
148
- if inputs.empty? or self.empty?
149
- return false
150
- end
151
-
152
- oldest_output_time = self.oldest_time
153
- newest_input_time = inputs.newest_time
154
-
155
- if newest_input_time and oldest_output_time
156
- # We are dirty if any inputs are newer (bigger) than any outputs:
157
- if newest_input_time > oldest_output_time
158
- return true
159
- else
160
- return false
161
- end
162
- end
163
-
164
- return true
165
- end
166
-
167
- def self.dirty?(inputs, outputs)
168
- outputs.dirty?(inputs)
169
- end
170
- end
171
- end
172
- end
@@ -1,90 +0,0 @@
1
- #!/usr/bin/env rspec
2
-
3
- # Copyright, 2015, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require 'build/files/monitor'
24
- require 'build/files/path'
25
- require 'build/files/system'
26
- require 'build/files/directory'
27
-
28
- RSpec.shared_examples_for Monitor do |driver|
29
- let(:root) {Build::Files::Path.expand('tmp', __dir__)}
30
- let(:path) {root + "test.txt"}
31
-
32
- before do
33
- root.delete
34
- root.create
35
- end
36
-
37
- let(:directory) {Build::Files::Directory.new(root)}
38
- let(:monitor) {Build::Files::Monitor.new}
39
-
40
- it "should include touched path" do
41
- path.touch
42
-
43
- expect(directory.to_a).to include(path)
44
- end
45
-
46
- it 'should detect additions' do
47
- changed = false
48
-
49
- monitor.track_changes(directory) do |state|
50
- changed = true
51
-
52
- expect(state.added).to include(path)
53
- end
54
-
55
- thread = Thread.new do
56
- sleep 1
57
- path.touch
58
- end
59
-
60
- monitor.run do
61
- throw :interrupt if changed
62
- end
63
-
64
- thread.join
65
-
66
- expect(changed).to be true
67
- end
68
-
69
- it "should add and remove monitored paths" do
70
- handler = monitor.track_changes(directory) do |state|
71
- # Do nothing.
72
- end
73
-
74
- expect(monitor.roots).to be_include root
75
-
76
- handler.remove!
77
-
78
- expect(monitor.roots).to be_empty
79
- end
80
- end
81
-
82
- RSpec.describe Build::Files::Monitor::Polling do
83
- it_behaves_like Monitor
84
- end
85
-
86
- if defined? Build::Files::Monitor::Native
87
- RSpec.describe Build::Files::Monitor::Native do
88
- it_behaves_like Monitor
89
- end
90
- end
@@ -1,90 +0,0 @@
1
- # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require 'build/files'
22
-
23
- module Build::Files::StateSpec
24
- describe Build::Files::State do
25
- let(:files) {Build::Files::Glob.new(__dir__, "*.rb")}
26
-
27
- it "should have no changes initially" do
28
- state = Build::Files::State.new(files)
29
-
30
- expect(state.update!).to be false
31
-
32
- expect(state.changed).to be == []
33
- expect(state.added).to be == []
34
- expect(state.removed).to be == []
35
- expect(state.missing).to be == []
36
- end
37
-
38
- it "should report missing files" do
39
- rebased_files = files.to_paths.rebase(File.join(__dir__, 'foo'))
40
- state = Build::Files::State.new(rebased_files)
41
-
42
- # Some changes were detected:
43
- expect(state.update!).to be true
44
-
45
- # Some files are missing:
46
- expect(state.missing).to_not be_empty
47
- end
48
-
49
- it "should not be confused by duplicates" do
50
- state = Build::Files::State.new(files + files)
51
-
52
- expect(state.update!).to be false
53
-
54
- expect(state.changed).to be == []
55
- expect(state.added).to be == []
56
- expect(state.removed).to be == []
57
- expect(state.missing).to be == []
58
- end
59
- end
60
-
61
- describe Build::Files::State do
62
- before(:each) do
63
- @temporary_files = Build::Files::Paths.directory(__dir__, ['a'])
64
- @temporary_files.touch
65
-
66
- @new_files = Build::Files::State.new(@temporary_files)
67
- @old_files = Build::Files::State.new(Build::Files::Glob.new(__dir__, "*.rb"))
68
- end
69
-
70
- after(:each) do
71
- @temporary_files.delete
72
- end
73
-
74
- let(:empty) {Build::Files::State.new(Build::Files::List::NONE)}
75
-
76
- it "should be clean with empty inputs or outputs" do
77
- expect(Build::Files::State.dirty?(empty, @new_files)).to be false
78
- expect(Build::Files::State.dirty?(@new_files, empty)).to be false
79
- end
80
-
81
- it "should be clean if files are newer" do
82
- expect(Build::Files::State.dirty?(@old_files, @new_files)).to be false
83
- end
84
-
85
- it "should be dirty if files are modified" do
86
- # In this case, the file mtime is usually different so...
87
- expect(Build::Files::State.dirty?(@new_files, @old_files)).to be true
88
- end
89
- end
90
- end