listen 2.10.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,45 @@
1
+ module Listen
2
+ class Listener
3
+ class Config
4
+ DEFAULTS = {
5
+ # Listener options
6
+ debug: false, # TODO: is this broken?
7
+ wait_for_delay: nil, # NOTE: should be provided by adapter if possible
8
+ relative: false,
9
+
10
+ # Backend selecting options
11
+ force_polling: false,
12
+ polling_fallback_message: nil
13
+ }
14
+
15
+ def initialize(opts)
16
+ @options = DEFAULTS.merge(opts)
17
+ @relative = @options[:relative]
18
+ @min_delay_between_events = @options[:wait_for_delay]
19
+ @silencer_rules = @options # silencer will extract what it needs
20
+ end
21
+
22
+ def relative?
23
+ @relative
24
+ end
25
+
26
+ def min_delay_between_events
27
+ @min_delay_between_events
28
+ end
29
+
30
+ def silencer_rules
31
+ @silencer_rules
32
+ end
33
+
34
+ def adapter_instance_options(klass)
35
+ valid_keys = klass.const_get('DEFAULTS').keys
36
+ Hash[@options.select { |key, _| valid_keys.include?(key) }]
37
+ end
38
+
39
+ def adapter_select_options
40
+ valid_keys = %w(force_polling polling_fallback_message).map(&:to_sym)
41
+ Hash[@options.select { |key, _| valid_keys.include?(key) }]
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,32 @@
1
+ module Listen
2
+ def self.logger
3
+ @logger
4
+ end
5
+
6
+ def self.logger=(logger)
7
+ @logger = logger
8
+ end
9
+
10
+ def self.setup_default_logger_if_unset
11
+ self.logger ||= ::Logger.new(STDERR).tap do |logger|
12
+ debugging = ENV['LISTEN_GEM_DEBUGGING']
13
+ logger.level =
14
+ case debugging.to_s
15
+ when /2/
16
+ ::Logger::DEBUG
17
+ when /true|yes|1/i
18
+ ::Logger::INFO
19
+ else
20
+ ::Logger::ERROR
21
+ end
22
+ end
23
+ end
24
+
25
+ class Logger
26
+ %i(fatal error warn info debug).each do |meth|
27
+ define_singleton_method(meth) do |*args, &block|
28
+ Listen.logger.public_send(meth, *args, &block) if Listen.logger
29
+ end
30
+ end
31
+ end
32
+ end
@@ -10,7 +10,7 @@ module Listen
10
10
  return if given_options.empty?
11
11
 
12
12
  msg = "Unknown options: #{given_options.inspect}"
13
- Celluloid::Logger.warn msg
13
+ Listen::Logger.warn msg
14
14
  fail msg
15
15
  end
16
16
 
@@ -1,23 +1,40 @@
1
1
  module Listen
2
- module QueueOptimizer
3
- private
2
+ class QueueOptimizer
3
+ class Config
4
+ def initialize(adapter_class, silencer)
5
+ @adapter_class = adapter_class
6
+ @silencer = silencer
7
+ end
8
+
9
+ def exist?(path)
10
+ Pathname(path).exist?
11
+ end
12
+
13
+ def silenced?(path, type)
14
+ @silencer.silenced?(path, type)
15
+ end
16
+
17
+ def debug(*args, &block)
18
+ Listen.logger.debug(*args, &block)
19
+ end
20
+ end
4
21
 
5
- def _smoosh_changes(changes)
22
+ def smoosh_changes(changes)
6
23
  # TODO: adapter could be nil at this point (shutdown)
7
- if _adapter_class.local_fs?
8
- cookies = changes.group_by do |_, _, _, _, options|
9
- (options || {})[:cookie]
10
- end
11
- _squash_changes(_reinterpret_related_changes(cookies))
12
- else
13
- smooshed = { modified: [], added: [], removed: [] }
14
- changes.each do |_, change, dir, rel_path, _|
15
- smooshed[change] << (dir + rel_path).to_s if smooshed.key?(change)
16
- end
17
- smooshed.tap { |s| s.each { |_, v| v.uniq! } }
24
+ cookies = changes.group_by do |_, _, _, _, options|
25
+ (options || {})[:cookie]
18
26
  end
27
+ _squash_changes(_reinterpret_related_changes(cookies))
28
+ end
29
+
30
+ def initialize(config)
31
+ @config = config
19
32
  end
20
33
 
34
+ private
35
+
36
+ attr_reader :config
37
+
21
38
  # groups changes into the expected structure expected by
22
39
  # clients
23
40
  def _squash_changes(changes)
@@ -28,13 +45,14 @@ module Listen
28
45
  actions = changes.group_by(&:last).map do |path, action_list|
29
46
  [_logical_action_for(path, action_list.map(&:first)), path.to_s]
30
47
  end
31
- _log :info, "listen: raw changes: #{actions.inspect}"
48
+
49
+ config.debug("listen: raw changes: #{actions.inspect}")
32
50
 
33
51
  { modified: [], added: [], removed: [] }.tap do |squashed|
34
52
  actions.each do |type, path|
35
53
  squashed[type] << path unless type.nil?
36
54
  end
37
- _log :info, "listen: final changes: #{squashed.inspect}"
55
+ config.debug("listen: final changes: #{squashed.inspect}")
38
56
  end
39
57
  end
40
58
 
@@ -53,7 +71,7 @@ module Listen
53
71
 
54
72
  # TODO: avoid checking if path exists and instead assume the events are
55
73
  # in order (if last is :removed, it doesn't exist, etc.)
56
- if path.exist?
74
+ if config.exist?(path)
57
75
  if diff > 0
58
76
  :added
59
77
  elsif diff.zero? && added > 0
@@ -77,7 +95,7 @@ module Listen
77
95
  [[:modified, to_dir, to_file]]
78
96
  else
79
97
  not_silenced = changes.reject do |type, _, _, path, _|
80
- _silenced?(Pathname(path), type)
98
+ config.silenced?(Pathname(path), type)
81
99
  end
82
100
  not_silenced.map do |_, change, dir, path, _|
83
101
  [table.fetch(change, change), dir, path]
@@ -107,8 +125,8 @@ module Listen
107
125
 
108
126
  # Expect an ignored moved_from and non-ignored moved_to
109
127
  # to qualify as an "editor modify"
110
- return unless _silenced?(Pathname(from), from_type)
111
- _silenced?(Pathname(to), to_type) ? nil : [to_dir, to]
128
+ return unless config.silenced?(Pathname(from), from_type)
129
+ config.silenced?(Pathname(to), to_type) ? nil : [to_dir, to]
112
130
  end
113
131
  end
114
132
  end
data/lib/listen/record.rb CHANGED
@@ -3,55 +3,53 @@ require 'listen/record/symlink_detector'
3
3
 
4
4
  module Listen
5
5
  class Record
6
- include Celluloid
7
6
  # TODO: one Record object per watched directory?
8
-
9
7
  # TODO: deprecate
10
- attr_accessor :paths, :listener
11
8
 
12
- def initialize(listener)
13
- @listener = listener
14
- @paths = _auto_hash
9
+ attr_reader :root
10
+ def initialize(directory)
11
+ @tree = _auto_hash
12
+ @root = directory.to_s
15
13
  end
16
14
 
17
- def add_dir(dir, rel_path)
15
+ def add_dir(rel_path)
18
16
  return if [nil, '', '.'].include? rel_path
19
- @paths[dir.to_s][rel_path] ||= {}
17
+ @tree[rel_path] ||= {}
20
18
  end
21
19
 
22
- def update_file(dir, rel_path, data)
20
+ def update_file(rel_path, data)
23
21
  dirname, basename = Pathname(rel_path).split.map(&:to_s)
24
- _fast_update_file(dir, dirname, basename, data)
22
+ _fast_update_file(dirname, basename, data)
25
23
  end
26
24
 
27
- def unset_path(dir, rel_path)
25
+ def unset_path(rel_path)
28
26
  dirname, basename = Pathname(rel_path).split.map(&:to_s)
29
- _fast_unset_path(dir, dirname, basename)
27
+ _fast_unset_path(dirname, basename)
30
28
  end
31
29
 
32
- def file_data(dir, rel_path)
33
- root = @paths[dir.to_s]
30
+ def file_data(rel_path)
34
31
  dirname, basename = Pathname(rel_path).split.map(&:to_s)
35
32
  if [nil, '', '.'].include? dirname
36
- root[basename] ||= {}
37
- root[basename].dup
33
+ tree[basename] ||= {}
34
+ tree[basename].dup
38
35
  else
39
- root[dirname] ||= {}
40
- root[dirname][basename] ||= {}
41
- root[dirname][basename].dup
36
+ tree[dirname] ||= {}
37
+ tree[dirname][basename] ||= {}
38
+ tree[dirname][basename].dup
42
39
  end
43
40
  end
44
41
 
45
- def dir_entries(dir, rel_path)
46
- tree = if [nil, '', '.'].include? rel_path.to_s
47
- @paths[dir.to_s]
48
- else
49
- @paths[dir.to_s][rel_path.to_s] ||= _auto_hash
50
- @paths[dir.to_s][rel_path.to_s]
51
- end
42
+ def dir_entries(rel_path)
43
+ subtree =
44
+ if [nil, '', '.'].include? rel_path.to_s
45
+ tree
46
+ else
47
+ tree[rel_path.to_s] ||= _auto_hash
48
+ tree[rel_path.to_s]
49
+ end
52
50
 
53
51
  result = {}
54
- tree.each do |key, values|
52
+ subtree.each do |key, values|
55
53
  # only get data for file entries
56
54
  result[key] = values.key?(:mtime) ? values : {}
57
55
  end
@@ -59,18 +57,14 @@ module Listen
59
57
  end
60
58
 
61
59
  def build
62
- start = Time.now.to_f
63
- @paths = _auto_hash
64
-
65
- # TODO: refactor this out (1 Record = 1 watched dir)
66
- listener.directories.each do |directory|
67
- _fast_build(directory.to_s)
68
- end
69
-
70
- Celluloid::Logger.info "Record.build(): #{Time.now.to_f - start} seconds"
71
- rescue
72
- Celluloid::Logger.warn "build crashed: #{$ERROR_INFO.inspect}"
73
- raise
60
+ @tree = _auto_hash
61
+ # TODO: test with a file name given
62
+ # TODO: test other permissions
63
+ # TODO: test with mixed encoding
64
+ symlink_detector = SymlinkDetector.new
65
+ remaining = Queue.new
66
+ remaining << Entry.new(root, nil, nil)
67
+ _fast_build_dir(remaining, symlink_detector) until remaining.empty?
74
68
  end
75
69
 
76
70
  private
@@ -79,56 +73,47 @@ module Listen
79
73
  Hash.new { |h, k| h[k] = Hash.new }
80
74
  end
81
75
 
82
- def _fast_update_file(dir, dirname, basename, data)
83
- root = @paths[dir.to_s]
76
+ def tree
77
+ @tree
78
+ end
79
+
80
+ def _fast_update_file(dirname, basename, data)
84
81
  if [nil, '', '.'].include? dirname
85
- root[basename] = (root[basename] || {}).merge(data)
82
+ tree[basename] = (tree[basename] || {}).merge(data)
86
83
  else
87
- root[dirname] ||= {}
88
- root[dirname][basename] = (root[dirname][basename] || {}).merge(data)
84
+ tree[dirname] ||= {}
85
+ tree[dirname][basename] = (tree[dirname][basename] || {}).merge(data)
89
86
  end
90
87
  end
91
88
 
92
- def _fast_unset_path(dir, dirname, basename)
93
- root = @paths[dir.to_s]
89
+ def _fast_unset_path(dirname, basename)
94
90
  # this may need to be reworked to properly remove
95
91
  # entries from a tree, without adding non-existing dirs to the record
96
92
  if [nil, '', '.'].include? dirname
97
- return unless root.key?(basename)
98
- root.delete(basename)
93
+ return unless tree.key?(basename)
94
+ tree.delete(basename)
99
95
  else
100
- return unless root.key?(dirname)
101
- root[dirname].delete(basename)
96
+ return unless tree.key?(dirname)
97
+ tree[dirname].delete(basename)
102
98
  end
103
99
  end
104
100
 
105
- # TODO: test with a file name given
106
- # TODO: test other permissions
107
- # TODO: test with mixed encoding
108
- def _fast_build(root)
109
- symlink_detector = SymlinkDetector.new
110
- @paths[root] = _auto_hash
111
- remaining = Queue.new
112
- remaining << Entry.new(root, nil, nil)
113
- _fast_build_dir(remaining, symlink_detector) until remaining.empty?
114
- end
115
-
116
101
  def _fast_build_dir(remaining, symlink_detector)
117
102
  entry = remaining.pop
118
103
  children = entry.children # NOTE: children() implicitly tests if dir
119
104
  symlink_detector.verify_unwatched!(entry)
120
105
  children.each { |child| remaining << child }
121
- add_dir(entry.root, entry.record_dir_key)
106
+ add_dir(entry.record_dir_key)
122
107
  rescue Errno::ENOTDIR
123
108
  _fast_try_file(entry)
124
109
  rescue SystemCallError, SymlinkDetector::Error
125
- _fast_unset_path(entry.root, entry.relative, entry.name)
110
+ _fast_unset_path(entry.relative, entry.name)
126
111
  end
127
112
 
128
113
  def _fast_try_file(entry)
129
- _fast_update_file(entry.root, entry.relative, entry.name, entry.meta)
114
+ _fast_update_file(entry.relative, entry.name, entry.meta)
130
115
  rescue SystemCallError
131
- _fast_unset_path(entry.root, entry.relative, entry.name)
116
+ _fast_unset_path(entry.relative, entry.name)
132
117
  end
133
118
  end
134
119
  end
@@ -0,0 +1,48 @@
1
+ module Listen
2
+ class Silencer
3
+ class Controller
4
+ def initialize(silencer, default_options)
5
+ @silencer = silencer
6
+
7
+ opts = default_options
8
+
9
+ @prev_silencer_options = {}
10
+ rules = [:only, :ignore, :ignore!].map do |option|
11
+ [option, opts[option]] if opts.key? option
12
+ end
13
+
14
+ _reconfigure_silencer(Hash[rules.compact])
15
+ end
16
+
17
+ def append_ignores(*regexps)
18
+ prev_ignores = Array(@prev_silencer_options[:ignore])
19
+ _reconfigure_silencer(ignore: [prev_ignores + regexps])
20
+ end
21
+
22
+ def replace_with_bang_ignores(regexps)
23
+ _reconfigure_silencer(ignore!: regexps)
24
+ end
25
+
26
+ def replace_with_only(regexps)
27
+ _reconfigure_silencer(only: regexps)
28
+ end
29
+
30
+ private
31
+
32
+ def _reconfigure_silencer(extra_options)
33
+ opts = extra_options.dup
34
+ opts = opts.map do |key, value|
35
+ [key, Array(value).flatten.compact]
36
+ end
37
+ opts = Hash[opts]
38
+
39
+ if opts.key?(:ignore) && opts[:ignore].empty?
40
+ opts.delete(:ignore)
41
+ end
42
+
43
+ @prev_silencer_options = opts
44
+ @silencer.configure(@prev_silencer_options.dup.freeze)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,3 @@
1
1
  module Listen
2
- VERSION = '2.10.1'
2
+ VERSION = '3.0.0'
3
3
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: listen
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.10.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thibaud Guillaume-Gentil
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-17 00:00:00.000000000 Z
11
+ date: 2015-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: celluloid
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 0.16.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.16.0
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: rb-fsevent
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -83,27 +69,32 @@ files:
83
69
  - lib/listen/adapter.rb
84
70
  - lib/listen/adapter/base.rb
85
71
  - lib/listen/adapter/bsd.rb
72
+ - lib/listen/adapter/config.rb
86
73
  - lib/listen/adapter/darwin.rb
87
74
  - lib/listen/adapter/linux.rb
88
75
  - lib/listen/adapter/polling.rb
89
- - lib/listen/adapter/tcp.rb
90
76
  - lib/listen/adapter/windows.rb
77
+ - lib/listen/backend.rb
91
78
  - lib/listen/change.rb
92
79
  - lib/listen/cli.rb
93
80
  - lib/listen/directory.rb
81
+ - lib/listen/event/config.rb
82
+ - lib/listen/event/loop.rb
83
+ - lib/listen/event/processor.rb
84
+ - lib/listen/event/queue.rb
94
85
  - lib/listen/file.rb
95
- - lib/listen/internals/logging.rb
86
+ - lib/listen/fsm.rb
96
87
  - lib/listen/internals/thread_pool.rb
97
88
  - lib/listen/listener.rb
89
+ - lib/listen/listener/config.rb
90
+ - lib/listen/logger.rb
98
91
  - lib/listen/options.rb
99
92
  - lib/listen/queue_optimizer.rb
100
93
  - lib/listen/record.rb
101
94
  - lib/listen/record/entry.rb
102
95
  - lib/listen/record/symlink_detector.rb
103
96
  - lib/listen/silencer.rb
104
- - lib/listen/tcp.rb
105
- - lib/listen/tcp/broadcaster.rb
106
- - lib/listen/tcp/message.rb
97
+ - lib/listen/silencer/controller.rb
107
98
  - lib/listen/version.rb
108
99
  homepage: https://github.com/guard/listen
109
100
  licenses: