listen 0.4.2 → 0.4.3

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 CHANGED
@@ -1,3 +1,16 @@
1
+ ## 0.4.3 - June 6, 2012
2
+
3
+ ### Bug fixes
4
+
5
+ - [#24](https://github.com/guard/listen/issues/24): Fail gracefully when the inotify limit is not enough for Listen to function. (reported by [@daemonza][], fixed by [@Maher4Ever][])
6
+ - [#32](https://github.com/guard/listen/issues/32): Fix a crash when trying to calculate the checksum of unreadable files. (reported by [@nex3][], fixed by [@Maher4Ever][])
7
+
8
+ ### Improvements
9
+
10
+ - Add `#relative_paths` method to listeners. ([@Maher4Ever][])
11
+ - Add `#started?` query-method to adapters. ([@Maher4Ever][])
12
+ - Dynamically detect the mtime precision used on a system. ([@Maher4Ever][] with help from [@nex3][])
13
+
1
14
  ## 0.4.2 - May 1, 2012
2
15
 
3
16
  ### Bug fixes
@@ -88,3 +101,4 @@
88
101
  [@akerbos]: https://github.com/akerbos
89
102
  [@fny]: https://github.com/fny
90
103
  [@cobychapple]: https://github.com/cobychapple
104
+ [@nex3]: https://github.com/nex3
data/README.md CHANGED
@@ -32,12 +32,12 @@ Feel free to give your feeback via [Listen issues](https://github.com/guard/list
32
32
 
33
33
  ``` ruby
34
34
  # Listen to a single directory.
35
- Listen.to('dir/path/to/listen', filter: /\.rb$/, ignore: %r{ignored/path/}) do |modified, added, removed|
35
+ Listen.to('dir/path/to/listen', :filter => /\.rb$/, :ignore => %r{ignored/path/}) do |modified, added, removed|
36
36
  # ...
37
37
  end
38
38
 
39
39
  # Listen to multiple directories.
40
- Listen.to('dir/to/awesome_app', 'dir/to/other_app', filter: /\.rb$/, latency: 0.1) do |modified, added, removed|
40
+ Listen.to('dir/to/awesome_app', 'dir/to/other_app', :filter => /\.rb$/, :latency => 0.1) do |modified, added, removed|
41
41
  # ...
42
42
  end
43
43
  ```
@@ -193,6 +193,9 @@ These options can be set through `Listen.to` params or via methods (see the "Obj
193
193
  :latency => 0.5 # Set the delay (**in seconds**) between checking for changes
194
194
  # default: 0.1 sec (1.0 sec for polling)
195
195
 
196
+ :relative_paths => true # Enable the use of relative paths in the callback.
197
+ # default: false
198
+
196
199
  :force_polling => true # Force the use of the polling adapter
197
200
  # default: none
198
201
 
@@ -83,6 +83,14 @@ module Listen
83
83
  @turnstile.signal # ensure no thread is blocked
84
84
  end
85
85
 
86
+ # Returns whether the adapter is statred or not
87
+ #
88
+ # @return [Boolean] whether the adapter is started or not
89
+ #
90
+ def started?
91
+ @stop.nil? ? false : !@stop
92
+ end
93
+
86
94
  # Blocks the main thread until the poll thread
87
95
  # calls the callback.
88
96
  #
@@ -129,7 +137,7 @@ module Listen
129
137
  ensure
130
138
  Thread.kill(t) if t
131
139
  FileUtils.rm(test_file) if File.exists?(test_file)
132
- adapter.stop
140
+ adapter.stop if adapter && adapter.started?
133
141
  end
134
142
 
135
143
  private
@@ -1,22 +1,33 @@
1
1
  module Listen
2
2
  module Adapters
3
3
 
4
- # Watched INotify EVENTS
5
- #
6
- # @see http://www.tin.org/bin/man.cgi?section=7&topic=inotify
7
- # @see https://github.com/nex3/rb-inotify/blob/master/lib/rb-inotify/notifier.rb#L99-L177
8
- #
9
- EVENTS = %w[recursive attrib close modify move create delete delete_self move_self]
10
-
11
4
  # Listener implementation for Linux `inotify`.
12
5
  #
13
6
  class Linux < Adapter
14
7
 
8
+ # Watched inotify events
9
+ #
10
+ # @see http://www.tin.org/bin/man.cgi?section=7&topic=inotify
11
+ # @see https://github.com/nex3/rb-inotify/blob/master/lib/rb-inotify/notifier.rb#L99-L177
12
+ #
13
+ EVENTS = %w[recursive attrib close modify move create delete delete_self move_self]
14
+
15
+ # The message to show when the limit of inotify watchers is not enough
16
+ #
17
+ INOTIFY_LIMIT_MESSAGE = <<-EOS.gsub(/^\s*/, '')
18
+ Listen error: unable to monitor directories for changes.
19
+
20
+ Please head to https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers
21
+ for information on how to solve this issue.
22
+ EOS
23
+
15
24
  # Initializes the Adapter. See {Listen::Adapter#initialize} for more info.
16
25
  #
17
26
  def initialize(directories, options = {}, &callback)
18
27
  super
19
28
  @worker = init_worker
29
+ rescue Errno::ENOSPC
30
+ abort(INOTIFY_LIMIT_MESSAGE)
20
31
  end
21
32
 
22
33
  # Starts the adapter.
@@ -15,6 +15,15 @@ module Listen
15
15
 
16
16
  DEFAULT_IGNORED_EXTENSIONS = %w[.DS_Store]
17
17
 
18
+ # Defines the used precision based on the type of mtime returned by the
19
+ # system (whether its in milliseconds or just seconds)
20
+ #
21
+ HIGH_PRECISION_SUPPORTED = File.mtime(__FILE__).to_f.to_s[-2..-1] != '.0'
22
+
23
+ # Data structure used to save meta data about a path
24
+ #
25
+ MetaData = Struct.new(:type, :mtime)
26
+
18
27
  # Class methods
19
28
  #
20
29
  class << self
@@ -71,7 +80,7 @@ module Listen
71
80
  # Adds ignoring patterns to the record.
72
81
  #
73
82
  # @example Ignore some paths
74
- # ignore ".git", ".svn"
83
+ # ignore %r{^ignored/path/}, /man/
75
84
  #
76
85
  # @param [Regexp] regexp a pattern for ignoring paths
77
86
  #
@@ -86,8 +95,6 @@ module Listen
86
95
  #
87
96
  # @param [Regexp] regexp a pattern for filtering paths
88
97
  #
89
- # @return [Listen::Listener] the listener itself
90
- #
91
98
  def filter(*regexps)
92
99
  @filtering_patterns.merge(regexps)
93
100
  end
@@ -123,7 +130,6 @@ module Listen
123
130
  def build
124
131
  @paths = Hash.new { |h, k| h[k] = Hash.new }
125
132
  important_paths { |path| insert_path(path) }
126
- @updated_at = Time.now.to_f
127
133
  end
128
134
 
129
135
  # Detects changes in the passed directories, updates
@@ -139,12 +145,13 @@ module Listen
139
145
  def fetch_changes(directories, options = {})
140
146
  @changes = { :modified => [], :added => [], :removed => [] }
141
147
  directories = directories.sort_by { |el| el.length }.reverse # diff sub-dir first
148
+
142
149
  directories.each do |directory|
143
150
  next unless directory[@directory] # Path is or inside directory
144
151
  detect_modifications_and_removals(directory, options)
145
152
  detect_additions(directory, options)
146
153
  end
147
- @updated_at = Time.now.to_f
154
+
148
155
  @changes
149
156
  end
150
157
 
@@ -173,10 +180,10 @@ module Listen
173
180
  # @option options [Boolean] relative_paths whether or not to use relative paths for changes
174
181
  #
175
182
  def detect_modifications_and_removals(directory, options = {})
176
- @paths[directory].each do |basename, type|
183
+ @paths[directory].each do |basename, meta_data|
177
184
  path = File.join(directory, basename)
178
185
 
179
- case type
186
+ case meta_data.type
180
187
  when 'Dir'
181
188
  if File.directory?(path)
182
189
  detect_modifications_and_removals(path, options) if options[:recursive]
@@ -187,8 +194,15 @@ module Listen
187
194
  end
188
195
  when 'File'
189
196
  if File.exist?(path)
190
- new_mtime = File.mtime(path).to_f
191
- if @updated_at < new_mtime || (@updated_at == new_mtime && content_modified?(path))
197
+ new_mtime = mtime_of(path)
198
+
199
+ # First check if we are in the same second (to update checksums)
200
+ # before checking the time difference
201
+ if (meta_data.mtime.to_i == new_mtime.to_i && content_modified?(path)) || meta_data.mtime < new_mtime
202
+ # Update the meta data of the files
203
+ meta_data.mtime = new_mtime
204
+ @paths[directory][basename] = meta_data
205
+
192
206
  @changes[:modified] << (options[:relative_paths] ? relative_to_base(path) : path)
193
207
  end
194
208
  else
@@ -238,12 +252,14 @@ module Listen
238
252
  #
239
253
  def content_modified?(path)
240
254
  sha1_checksum = Digest::SHA1.file(path).to_s
241
- if @sha1_checksums[path] != sha1_checksum
242
- @sha1_checksums[path] = sha1_checksum
243
- true
244
- else
245
- false
246
- end
255
+ return false if @sha1_checksums[path] == sha1_checksum
256
+
257
+ had_no_checksum = @sha1_checksums[path].nil?
258
+ @sha1_checksums[path] = sha1_checksum
259
+
260
+ had_no_checksum ? false : true
261
+ rescue Errno::EACCES # unreadble file
262
+ false
247
263
  end
248
264
 
249
265
  # Traverses the base directory looking for paths that should
@@ -274,7 +290,10 @@ module Listen
274
290
  # @param [String] path the path to insert in @paths.
275
291
  #
276
292
  def insert_path(path)
277
- @paths[File.dirname(path)][File.basename(path)] = File.directory?(path) ? 'Dir' : 'File'
293
+ meta_data = MetaData.new
294
+ meta_data.type = File.directory?(path) ? 'Dir' : 'File'
295
+ meta_data.mtime = mtime_of(path) unless meta_data.type == 'Dir' # mtimes of dirs are not used yet
296
+ @paths[File.dirname(path)][File.basename(path)] = meta_data
278
297
  end
279
298
 
280
299
  # Returns whether or not a path exists in the paths hash.
@@ -286,5 +305,15 @@ module Listen
286
305
  def existing_path?(path)
287
306
  @paths[File.dirname(path)][File.basename(path)] != nil
288
307
  end
308
+
309
+ # Returns the modification time of a file based on the precision defined by the system
310
+ #
311
+ # @param [String] file the file for which the mtime must be returned
312
+ #
313
+ # @return [Fixnum, Float] the mtime of the file
314
+ #
315
+ def mtime_of(file)
316
+ File.mtime(file).send(HIGH_PRECISION_SUPPORTED ? :to_f : :to_i)
317
+ end
289
318
  end
290
319
  end
@@ -119,7 +119,7 @@ module Listen
119
119
  self
120
120
  end
121
121
 
122
- # Defines whether the use of the polling adapter
122
+ # Sets whether the use of the polling adapter
123
123
  # should be forced or not.
124
124
  #
125
125
  # @example Forcing the use of the polling adapter
@@ -134,6 +134,21 @@ module Listen
134
134
  self
135
135
  end
136
136
 
137
+ # Sets whether the paths in the callback should be
138
+ # relative or absolute.
139
+ #
140
+ # @example Enabling relative paths in the callback
141
+ # relative_paths true
142
+ #
143
+ # @param [Boolean] value whether to enable relative paths in the callback or not
144
+ #
145
+ # @return [Listen::Listener] the listener
146
+ #
147
+ def relative_paths(value)
148
+ @use_relative_paths = value
149
+ self
150
+ end
151
+
137
152
  # Defines a custom polling fallback message of disable it.
138
153
  #
139
154
  # @example Disabling the polling fallback message
@@ -1,3 +1,3 @@
1
1
  module Listen
2
- VERSION = '0.4.2'
2
+ VERSION = '0.4.3'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: listen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-05-01 00:00:00.000000000 Z
13
+ date: 2012-06-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rb-fsevent
17
- requirement: &14607320 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
@@ -22,10 +22,15 @@ dependencies:
22
22
  version: 0.9.1
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *14607320
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: 0.9.1
26
31
  - !ruby/object:Gem::Dependency
27
32
  name: rb-inotify
28
- requirement: &14606840 !ruby/object:Gem::Requirement
33
+ requirement: !ruby/object:Gem::Requirement
29
34
  none: false
30
35
  requirements:
31
36
  - - ~>
@@ -33,10 +38,15 @@ dependencies:
33
38
  version: 0.8.8
34
39
  type: :runtime
35
40
  prerelease: false
36
- version_requirements: *14606840
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 0.8.8
37
47
  - !ruby/object:Gem::Dependency
38
48
  name: rb-fchange
39
- requirement: &14606320 !ruby/object:Gem::Requirement
49
+ requirement: !ruby/object:Gem::Requirement
40
50
  none: false
41
51
  requirements:
42
52
  - - ~>
@@ -44,10 +54,15 @@ dependencies:
44
54
  version: 0.0.5
45
55
  type: :runtime
46
56
  prerelease: false
47
- version_requirements: *14606320
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 0.0.5
48
63
  - !ruby/object:Gem::Dependency
49
64
  name: bundler
50
- requirement: &14605920 !ruby/object:Gem::Requirement
65
+ requirement: !ruby/object:Gem::Requirement
51
66
  none: false
52
67
  requirements:
53
68
  - - ! '>='
@@ -55,7 +70,12 @@ dependencies:
55
70
  version: '0'
56
71
  type: :development
57
72
  prerelease: false
58
- version_requirements: *14605920
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
59
79
  description: The Listen gem listens to file modifications and notifies you about the
60
80
  changes. Works everywhere!
61
81
  email:
@@ -66,16 +86,16 @@ extensions: []
66
86
  extra_rdoc_files: []
67
87
  files:
68
88
  - lib/listen.rb
89
+ - lib/listen/version.rb
90
+ - lib/listen/adapter.rb
69
91
  - lib/listen/multi_listener.rb
70
- - lib/listen/directory_record.rb
71
92
  - lib/listen/listener.rb
72
- - lib/listen/version.rb
73
- - lib/listen/adapters/linux.rb
93
+ - lib/listen/turnstile.rb
94
+ - lib/listen/directory_record.rb
74
95
  - lib/listen/adapters/polling.rb
75
96
  - lib/listen/adapters/darwin.rb
97
+ - lib/listen/adapters/linux.rb
76
98
  - lib/listen/adapters/windows.rb
77
- - lib/listen/adapter.rb
78
- - lib/listen/turnstile.rb
79
99
  - CHANGELOG.md
80
100
  - LICENSE
81
101
  - README.md
@@ -91,6 +111,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
111
  - - ! '>='
92
112
  - !ruby/object:Gem::Version
93
113
  version: '0'
114
+ segments:
115
+ - 0
116
+ hash: -692640991
94
117
  required_rubygems_version: !ruby/object:Gem::Requirement
95
118
  none: false
96
119
  requirements:
@@ -99,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
122
  version: 1.3.6
100
123
  requirements: []
101
124
  rubyforge_project: listen
102
- rubygems_version: 1.8.17
125
+ rubygems_version: 1.8.24
103
126
  signing_key:
104
127
  specification_version: 3
105
128
  summary: Listen to file modifications