listen 0.5.3 → 3.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -186
  3. data/CONTRIBUTING.md +45 -0
  4. data/{LICENSE → LICENSE.txt} +3 -1
  5. data/README.md +332 -181
  6. data/bin/listen +11 -0
  7. data/lib/listen/adapter/base.rb +129 -0
  8. data/lib/listen/adapter/bsd.rb +107 -0
  9. data/lib/listen/adapter/config.rb +25 -0
  10. data/lib/listen/adapter/darwin.rb +77 -0
  11. data/lib/listen/adapter/linux.rb +108 -0
  12. data/lib/listen/adapter/polling.rb +40 -0
  13. data/lib/listen/adapter/windows.rb +96 -0
  14. data/lib/listen/adapter.rb +32 -201
  15. data/lib/listen/backend.rb +40 -0
  16. data/lib/listen/change.rb +69 -0
  17. data/lib/listen/cli.rb +65 -0
  18. data/lib/listen/directory.rb +93 -0
  19. data/lib/listen/error.rb +11 -0
  20. data/lib/listen/event/config.rb +40 -0
  21. data/lib/listen/event/loop.rb +94 -0
  22. data/lib/listen/event/processor.rb +126 -0
  23. data/lib/listen/event/queue.rb +54 -0
  24. data/lib/listen/file.rb +95 -0
  25. data/lib/listen/fsm.rb +133 -0
  26. data/lib/listen/listener/config.rb +41 -0
  27. data/lib/listen/listener.rb +93 -160
  28. data/lib/listen/logger.rb +36 -0
  29. data/lib/listen/monotonic_time.rb +27 -0
  30. data/lib/listen/options.rb +26 -0
  31. data/lib/listen/queue_optimizer.rb +129 -0
  32. data/lib/listen/record/entry.rb +66 -0
  33. data/lib/listen/record/symlink_detector.rb +41 -0
  34. data/lib/listen/record.rb +123 -0
  35. data/lib/listen/silencer/controller.rb +50 -0
  36. data/lib/listen/silencer.rb +106 -0
  37. data/lib/listen/thread.rb +54 -0
  38. data/lib/listen/version.rb +3 -1
  39. data/lib/listen.rb +40 -32
  40. metadata +87 -38
  41. data/lib/listen/adapters/darwin.rb +0 -85
  42. data/lib/listen/adapters/linux.rb +0 -113
  43. data/lib/listen/adapters/polling.rb +0 -67
  44. data/lib/listen/adapters/windows.rb +0 -87
  45. data/lib/listen/dependency_manager.rb +0 -126
  46. data/lib/listen/directory_record.rb +0 -344
  47. data/lib/listen/multi_listener.rb +0 -121
  48. data/lib/listen/turnstile.rb +0 -28
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thread'
4
+ require 'listen/record/entry'
5
+ require 'listen/record/symlink_detector'
6
+
7
+ module Listen
8
+ class Record
9
+ # TODO: one Record object per watched directory?
10
+ # TODO: deprecate
11
+
12
+ attr_reader :root
13
+
14
+ def initialize(directory, silencer)
15
+ reset_tree
16
+ @root = directory.to_s
17
+ @silencer = silencer
18
+ end
19
+
20
+ def add_dir(rel_path)
21
+ if !empty_dirname?(rel_path.to_s)
22
+ @tree[rel_path.to_s]
23
+ end
24
+ end
25
+
26
+ def update_file(rel_path, data)
27
+ dirname, basename = Pathname(rel_path).split.map(&:to_s)
28
+ _fast_update_file(dirname, basename, data)
29
+ end
30
+
31
+ def unset_path(rel_path)
32
+ dirname, basename = Pathname(rel_path).split.map(&:to_s)
33
+ _fast_unset_path(dirname, basename)
34
+ end
35
+
36
+ def file_data(rel_path)
37
+ dirname, basename = Pathname(rel_path).split.map(&:to_s)
38
+ if empty_dirname?(dirname)
39
+ @tree[basename].dup
40
+ else
41
+ @tree[dirname][basename] ||= {}
42
+ @tree[dirname][basename].dup
43
+ end
44
+ end
45
+
46
+ def dir_entries(rel_path)
47
+ rel_path_s = rel_path.to_s
48
+ subtree = if empty_dirname?(rel_path_s)
49
+ @tree
50
+ else
51
+ @tree[rel_path_s]
52
+ end
53
+
54
+ subtree.each_with_object({}) do |(key, values), result|
55
+ # only return data for file entries inside the dir (which will each be sub-hashes)
56
+ if values.is_a?(Hash)
57
+ result[key] = values.has_key?(:mtime) ? values : {}
58
+ end
59
+ end
60
+ end
61
+
62
+ def build
63
+ reset_tree
64
+ # TODO: test with a file name given
65
+ # TODO: test other permissions
66
+ # TODO: test with mixed encoding
67
+ symlink_detector = SymlinkDetector.new
68
+ remaining = ::Queue.new
69
+ remaining << Entry.new(root, nil, nil)
70
+ _fast_build_dir(remaining, symlink_detector) until remaining.empty?
71
+ end
72
+
73
+ private
74
+
75
+ def empty_dirname?(dirname)
76
+ dirname == '.' || dirname == ''
77
+ end
78
+
79
+ def reset_tree
80
+ @tree = Hash.new { |h, k| h[k] = {} }
81
+ end
82
+
83
+ def _fast_update_file(dirname, basename, data)
84
+ if empty_dirname?(dirname.to_s)
85
+ @tree[basename] = @tree[basename].merge(data)
86
+ else
87
+ @tree[dirname][basename] = (@tree[dirname][basename] || {}).merge(data)
88
+ end
89
+ end
90
+
91
+ def _fast_unset_path(dirname, basename)
92
+ # this may need to be reworked to properly remove
93
+ # entries from a tree, without adding non-existing dirs to the record
94
+ if empty_dirname?(dirname.to_s)
95
+ if @tree.key?(basename)
96
+ @tree.delete(basename)
97
+ end
98
+ elsif @tree.key?(dirname)
99
+ @tree[dirname].delete(basename)
100
+ end
101
+ end
102
+
103
+ def _fast_build_dir(remaining, symlink_detector)
104
+ entry = remaining.pop
105
+ return if @silencer.silenced?(entry.record_dir_key, :dir)
106
+
107
+ children = entry.children # NOTE: children() implicitly tests if dir
108
+ symlink_detector.verify_unwatched!(entry)
109
+ children.each { |child| remaining << child }
110
+ add_dir(entry.record_dir_key)
111
+ rescue Errno::ENOTDIR
112
+ _fast_try_file(entry)
113
+ rescue SystemCallError, SymlinkDetector::Error
114
+ _fast_unset_path(entry.relative, entry.name)
115
+ end
116
+
117
+ def _fast_try_file(entry)
118
+ _fast_update_file(entry.relative, entry.name, entry.meta)
119
+ rescue SystemCallError
120
+ _fast_unset_path(entry.relative, entry.name)
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Listen
4
+ class Silencer
5
+ class Controller
6
+ def initialize(silencer, default_options)
7
+ @silencer = silencer
8
+
9
+ opts = default_options
10
+
11
+ @prev_silencer_options = {}
12
+ rules = [:only, :ignore, :ignore!].map do |option|
13
+ [option, opts[option]] if opts.key? option
14
+ end
15
+
16
+ _reconfigure_silencer(Hash[rules.compact])
17
+ end
18
+
19
+ def append_ignores(*regexps)
20
+ prev_ignores = Array(@prev_silencer_options[:ignore])
21
+ _reconfigure_silencer(ignore: [prev_ignores + regexps])
22
+ end
23
+
24
+ def replace_with_bang_ignores(regexps)
25
+ _reconfigure_silencer(ignore!: regexps)
26
+ end
27
+
28
+ def replace_with_only(regexps)
29
+ _reconfigure_silencer(only: regexps)
30
+ end
31
+
32
+ private
33
+
34
+ def _reconfigure_silencer(extra_options)
35
+ opts = extra_options.dup
36
+ opts = opts.map do |key, value|
37
+ [key, Array(value).flatten.compact]
38
+ end
39
+ opts = Hash[opts]
40
+
41
+ if opts.key?(:ignore) && opts[:ignore].empty?
42
+ opts.delete(:ignore)
43
+ end
44
+
45
+ @prev_silencer_options = opts
46
+ @silencer.configure(@prev_silencer_options.dup.freeze)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Listen
4
+ class Silencer
5
+ # The default list of directories that get ignored.
6
+ DEFAULT_IGNORED_FILES = %r{\A(?:
7
+ \.git
8
+ | \.svn
9
+ | \.hg
10
+ | \.rbx
11
+ | \.bundle
12
+ | bundle
13
+ | vendor/bundle
14
+ | log
15
+ | tmp
16
+ | vendor/ruby
17
+
18
+ # emacs temp files
19
+ | \#.+\#
20
+ | \.\#.+
21
+ )(/|\z)}x.freeze
22
+
23
+ # The default list of files that get ignored.
24
+ DEFAULT_IGNORED_EXTENSIONS = %r{(?:
25
+ # Kate's tmp\/swp files
26
+ \..*\d+\.new
27
+ | \.kate-swp
28
+
29
+ # Gedit tmp files
30
+ | \.goutputstream-.{6}
31
+
32
+ # Intellij files
33
+ | ___jb_bak___
34
+ | ___jb_old___
35
+
36
+ # Vim swap files and write test
37
+ | \.sw[px]
38
+ | \.swpx
39
+ | ^4913
40
+
41
+ # Sed temporary files - but without actual words, like 'sedatives'
42
+ | (?:\A
43
+ sed
44
+
45
+ (?:
46
+ [a-zA-Z0-9]{0}[A-Z]{1}[a-zA-Z0-9]{5} |
47
+ [a-zA-Z0-9]{1}[A-Z]{1}[a-zA-Z0-9]{4} |
48
+ [a-zA-Z0-9]{2}[A-Z]{1}[a-zA-Z0-9]{3} |
49
+ [a-zA-Z0-9]{3}[A-Z]{1}[a-zA-Z0-9]{2} |
50
+ [a-zA-Z0-9]{4}[A-Z]{1}[a-zA-Z0-9]{1} |
51
+ [a-zA-Z0-9]{5}[A-Z]{1}[a-zA-Z0-9]{0}
52
+ )
53
+ )
54
+
55
+ # Mutagen sync temporary files
56
+ | \.mutagen-temporary.*
57
+
58
+ # other files
59
+ | \.DS_Store
60
+ | \.tmp
61
+ | ~
62
+ )\z}x.freeze
63
+
64
+ # TODO: deprecate these mutators; use attr_reader instead
65
+ attr_accessor :only_patterns, :ignore_patterns
66
+
67
+ def initialize(**options)
68
+ configure(options)
69
+ end
70
+
71
+ # TODO: deprecate this mutator
72
+ def configure(options)
73
+ @only_patterns = options[:only] ? Array(options[:only]) : nil
74
+ @ignore_patterns = _init_ignores(options[:ignore], options[:ignore!])
75
+ end
76
+
77
+ def silenced?(relative_path, type)
78
+ path = relative_path.to_s # in case it is a Pathname
79
+
80
+ _ignore?(path) || (only_patterns && type == :file && !_only?(path))
81
+ end
82
+
83
+ private
84
+
85
+ def _ignore?(path)
86
+ ignore_patterns.any? { |pattern| path =~ pattern }
87
+ end
88
+
89
+ def _only?(path)
90
+ only_patterns.any? { |pattern| path =~ pattern }
91
+ end
92
+
93
+ def _init_ignores(ignores, overrides)
94
+ patterns = []
95
+ unless overrides
96
+ patterns << DEFAULT_IGNORED_FILES
97
+ patterns << DEFAULT_IGNORED_EXTENSIONS
98
+ end
99
+
100
+ patterns << ignores
101
+ patterns << overrides
102
+
103
+ patterns.compact.flatten
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thread'
4
+
5
+ require_relative 'logger'
6
+
7
+ module Listen
8
+ module Thread
9
+ class << self
10
+ # Creates a new thread with the given name.
11
+ # Any exceptions raised by the thread will be logged with the thread name and complete backtrace.
12
+ # rubocop:disable Style/MultilineBlockChain
13
+ def new(name, &block)
14
+ thread_name = "listen-#{name}"
15
+ caller_stack = caller
16
+
17
+ ::Thread.new do
18
+ rescue_and_log(thread_name, caller_stack: caller_stack, &block)
19
+ end.tap do |thread|
20
+ thread.name = thread_name
21
+ end
22
+ end
23
+ # rubocop:enable Style/MultilineBlockChain
24
+
25
+ def rescue_and_log(method_name, *args, caller_stack: nil)
26
+ yield(*args)
27
+ rescue => exception
28
+ _log_exception(exception, method_name, caller_stack: caller_stack)
29
+ end
30
+
31
+ private
32
+
33
+ def _log_exception(exception, thread_name, caller_stack: nil)
34
+ complete_backtrace = if caller_stack
35
+ [*exception.backtrace, "--- Thread.new ---", *caller_stack]
36
+ else
37
+ exception.backtrace
38
+ end
39
+ message = "Exception rescued in #{thread_name}:\n#{_exception_with_causes(exception)}\n#{complete_backtrace * "\n"}"
40
+ Listen.logger.error(message)
41
+ end
42
+
43
+ def _exception_with_causes(exception)
44
+ result = +"#{exception.class}: #{exception}"
45
+ if exception.cause
46
+ result << "\n"
47
+ result << "--- Caused by: ---\n"
48
+ result << _exception_with_causes(exception.cause)
49
+ end
50
+ result
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Listen
2
- VERSION = '0.5.3'
4
+ VERSION = '3.7.1'
3
5
  end
data/lib/listen.rb CHANGED
@@ -1,39 +1,47 @@
1
- module Listen
1
+ # frozen_string_literal: true
2
2
 
3
- autoload :Turnstile, 'listen/turnstile'
4
- autoload :Listener, 'listen/listener'
5
- autoload :MultiListener, 'listen/multi_listener'
6
- autoload :DirectoryRecord, 'listen/directory_record'
7
- autoload :DependencyManager, 'listen/dependency_manager'
8
- autoload :Adapter, 'listen/adapter'
3
+ require 'logger'
4
+ require 'weakref'
5
+ require 'listen/logger'
6
+ require 'listen/listener'
9
7
 
10
- module Adapters
11
- autoload :Darwin, 'listen/adapters/darwin'
12
- autoload :Linux, 'listen/adapters/linux'
13
- autoload :Windows, 'listen/adapters/windows'
14
- autoload :Polling, 'listen/adapters/polling'
15
- end
8
+ # Won't print anything by default because of level - unless you've set
9
+ # LISTEN_GEM_DEBUGGING or provided your own logger with a high enough level
10
+ Listen.logger.info "Listen loglevel set to: #{Listen.logger.level}"
11
+ Listen.logger.info "Listen version: #{Listen::VERSION}"
12
+
13
+ module Listen
14
+ @listeners = Queue.new
16
15
 
17
- # Listens to filesystem modifications on a either single directory or multiple directories.
18
- #
19
- # @param (see Listen::Listener#new)
20
- # @param (see Listen::MultiListener#new)
21
- #
22
- # @yield [modified, added, removed] the changed files
23
- # @yieldparam [Array<String>] modified the list of modified files
24
- # @yieldparam [Array<String>] added the list of added files
25
- # @yieldparam [Array<String>] removed the list of removed files
26
- #
27
- # @return [Listen::Listener] the file listener if no block given
28
- #
29
- def self.to(*args, &block)
30
- listener = if args.length == 1 || ! args[1].is_a?(String)
31
- Listener.new(*args, &block)
32
- else
33
- MultiListener.new(*args, &block)
16
+ class << self
17
+ # Listens to file system modifications on a either single directory or
18
+ # multiple directories.
19
+ #
20
+ # @param (see Listen::Listener#new)
21
+ #
22
+ # @yield [modified, added, removed] the changed files
23
+ # @yieldparam [Array<String>] modified the list of modified files
24
+ # @yieldparam [Array<String>] added the list of added files
25
+ # @yieldparam [Array<String>] removed the list of removed files
26
+ #
27
+ # @return [Listen::Listener] the listener
28
+ #
29
+ def to(*args, &block)
30
+ Listener.new(*args, &block).tap do |listener|
31
+ @listeners.enq(WeakRef.new(listener))
32
+ end
34
33
  end
35
34
 
36
- block ? listener.start : listener
35
+ # This is used by the `listen` binary to handle Ctrl-C
36
+ #
37
+ def stop
38
+ while (listener = @listeners.deq(true))
39
+ begin
40
+ listener.stop
41
+ rescue WeakRef::RefError
42
+ end
43
+ end
44
+ rescue ThreadError
45
+ end
37
46
  end
38
-
39
47
  end
metadata CHANGED
@@ -1,79 +1,128 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: listen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
5
- prerelease:
4
+ version: 3.7.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Thibaud Guillaume-Gentil
9
- - Maher Sallam
10
8
  autorequire:
11
9
  bindir: bin
12
10
  cert_chain: []
13
- date: 2012-10-03 00:00:00.000000000 Z
11
+ date: 2022-01-13 00:00:00.000000000 Z
14
12
  dependencies:
15
13
  - !ruby/object:Gem::Dependency
16
- name: bundler
14
+ name: rb-fsevent
17
15
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
16
  requirements:
20
- - - ! '>='
17
+ - - "~>"
21
18
  - !ruby/object:Gem::Version
22
- version: '0'
23
- type: :development
19
+ version: '0.10'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.10.3
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.10'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.10.3
33
+ - !ruby/object:Gem::Dependency
34
+ name: rb-inotify
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.9'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 0.9.10
43
+ type: :runtime
24
44
  prerelease: false
25
45
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
46
  requirements:
28
- - - ! '>='
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '0.9'
50
+ - - ">="
29
51
  - !ruby/object:Gem::Version
30
- version: '0'
52
+ version: 0.9.10
31
53
  description: The Listen gem listens to file modifications and notifies you about the
32
54
  changes. Works everywhere!
33
- email:
34
- - thibaud@thibaud.me
35
- - maher@sallam.me
36
- executables: []
55
+ email: thibaud@thibaud.gg
56
+ executables:
57
+ - listen
37
58
  extensions: []
38
59
  extra_rdoc_files: []
39
60
  files:
61
+ - CHANGELOG.md
62
+ - CONTRIBUTING.md
63
+ - LICENSE.txt
64
+ - README.md
65
+ - bin/listen
66
+ - lib/listen.rb
40
67
  - lib/listen/adapter.rb
41
- - lib/listen/adapters/darwin.rb
42
- - lib/listen/adapters/linux.rb
43
- - lib/listen/adapters/polling.rb
44
- - lib/listen/adapters/windows.rb
45
- - lib/listen/dependency_manager.rb
46
- - lib/listen/directory_record.rb
68
+ - lib/listen/adapter/base.rb
69
+ - lib/listen/adapter/bsd.rb
70
+ - lib/listen/adapter/config.rb
71
+ - lib/listen/adapter/darwin.rb
72
+ - lib/listen/adapter/linux.rb
73
+ - lib/listen/adapter/polling.rb
74
+ - lib/listen/adapter/windows.rb
75
+ - lib/listen/backend.rb
76
+ - lib/listen/change.rb
77
+ - lib/listen/cli.rb
78
+ - lib/listen/directory.rb
79
+ - lib/listen/error.rb
80
+ - lib/listen/event/config.rb
81
+ - lib/listen/event/loop.rb
82
+ - lib/listen/event/processor.rb
83
+ - lib/listen/event/queue.rb
84
+ - lib/listen/file.rb
85
+ - lib/listen/fsm.rb
47
86
  - lib/listen/listener.rb
48
- - lib/listen/multi_listener.rb
49
- - lib/listen/turnstile.rb
87
+ - lib/listen/listener/config.rb
88
+ - lib/listen/logger.rb
89
+ - lib/listen/monotonic_time.rb
90
+ - lib/listen/options.rb
91
+ - lib/listen/queue_optimizer.rb
92
+ - lib/listen/record.rb
93
+ - lib/listen/record/entry.rb
94
+ - lib/listen/record/symlink_detector.rb
95
+ - lib/listen/silencer.rb
96
+ - lib/listen/silencer/controller.rb
97
+ - lib/listen/thread.rb
50
98
  - lib/listen/version.rb
51
- - lib/listen.rb
52
- - CHANGELOG.md
53
- - LICENSE
54
- - README.md
55
99
  homepage: https://github.com/guard/listen
56
- licenses: []
100
+ licenses:
101
+ - MIT
102
+ metadata:
103
+ allowed_push_host: https://rubygems.org
104
+ bug_tracker_uri: https://github.com/guard/listen/issues
105
+ changelog_uri: https://github.com/guard/listen/releases
106
+ documentation_uri: https://www.rubydoc.info/gems/listen/3.7.1
107
+ homepage_uri: https://github.com/guard/listen
108
+ source_code_uri: https://github.com/guard/listen/tree/v3.7.1
57
109
  post_install_message:
58
110
  rdoc_options: []
59
111
  require_paths:
60
112
  - lib
61
113
  required_ruby_version: !ruby/object:Gem::Requirement
62
- none: false
63
114
  requirements:
64
- - - ! '>='
115
+ - - ">="
65
116
  - !ruby/object:Gem::Version
66
- version: '0'
117
+ version: 2.4.0
67
118
  required_rubygems_version: !ruby/object:Gem::Requirement
68
- none: false
69
119
  requirements:
70
- - - ! '>='
120
+ - - ">="
71
121
  - !ruby/object:Gem::Version
72
- version: 1.3.6
122
+ version: '0'
73
123
  requirements: []
74
- rubyforge_project: listen
75
- rubygems_version: 1.8.23
124
+ rubygems_version: 3.0.1
76
125
  signing_key:
77
- specification_version: 3
126
+ specification_version: 4
78
127
  summary: Listen to file modifications
79
128
  test_files: []
@@ -1,85 +0,0 @@
1
- module Listen
2
- module Adapters
3
-
4
- # Adapter implementation for Mac OS X `FSEvents`.
5
- #
6
- class Darwin < Adapter
7
- extend DependencyManager
8
-
9
- # Declare the adapter's dependencies
10
- dependency 'rb-fsevent', '~> 0.9.1'
11
-
12
- LAST_SEPARATOR_REGEX = /\/$/
13
-
14
- # Initializes the Adapter. See {Listen::Adapter#initialize} for more info.
15
- #
16
- def initialize(directories, options = {}, &callback)
17
- super
18
- @worker = init_worker
19
- end
20
-
21
- # Starts the adapter.
22
- #
23
- # @param [Boolean] blocking whether or not to block the current thread after starting
24
- #
25
- def start(blocking = true)
26
- @mutex.synchronize do
27
- return if @stop == false
28
- super
29
- end
30
-
31
- @worker_thread = Thread.new { @worker.run }
32
-
33
- # The FSEvent worker needs sometime to startup. Turnstiles can't
34
- # be used to wait for it as it runs in a loop.
35
- # TODO: Find a better way to block until the worker starts.
36
- sleep 0.1
37
-
38
- @poll_thread = Thread.new { poll_changed_dirs } if @report_changes
39
- @worker_thread.join if blocking
40
- end
41
-
42
- # Stops the adapter.
43
- #
44
- def stop
45
- @mutex.synchronize do
46
- return if @stop == true
47
- super
48
- end
49
-
50
- @worker.stop
51
- @worker_thread.join if @worker_thread
52
- @poll_thread.join if @poll_thread
53
- end
54
-
55
- # Checks if the adapter is usable on the current OS.
56
- #
57
- # @return [Boolean] whether usable or not
58
- #
59
- def self.usable?
60
- return false unless RbConfig::CONFIG['target_os'] =~ /darwin(1.+)?$/i
61
- super
62
- end
63
-
64
- private
65
-
66
- # Initializes a FSEvent worker and adds a watcher for
67
- # each directory passed to the adapter.
68
- #
69
- # @return [FSEvent] initialized worker
70
- #
71
- def init_worker
72
- FSEvent.new.tap do |worker|
73
- worker.watch(@directories.dup, :latency => @latency) do |changes|
74
- next if @paused
75
- @mutex.synchronize do
76
- changes.each { |path| @changed_dirs << path.sub(LAST_SEPARATOR_REGEX, '') }
77
- end
78
- end
79
- end
80
- end
81
-
82
- end
83
-
84
- end
85
- end