listen 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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