dtas 0.15.0 → 0.18.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -1
- data/Documentation/.gitignore +1 -1
- data/Documentation/GNUmakefile +2 -2
- data/Documentation/dtas-archive.pod +2 -2
- data/Documentation/dtas-console.pod +2 -2
- data/Documentation/dtas-ctl.pod +2 -2
- data/Documentation/dtas-cueedit.pod +2 -2
- data/Documentation/dtas-enq.pod +2 -2
- data/Documentation/dtas-env.pod +3 -3
- data/Documentation/dtas-msinkctl.pod +2 -2
- data/Documentation/dtas-player.pod +2 -2
- data/Documentation/dtas-player_effects.pod +2 -2
- data/Documentation/dtas-player_protocol.pod +4 -4
- data/Documentation/dtas-player_sink_examples.pod +2 -2
- data/Documentation/dtas-sinkedit.pod +4 -4
- data/Documentation/dtas-sourceedit.pod +4 -4
- data/Documentation/dtas-splitfx.pod +7 -1
- data/Documentation/dtas-tl.pod +4 -4
- data/Documentation/dtas-xdelay.pod +2 -2
- data/Documentation/update-footer.rb +2 -2
- data/GIT-VERSION-GEN +2 -2
- data/GNUmakefile +1 -1
- data/HACKING +2 -2
- data/INSTALL +13 -24
- data/README +14 -8
- data/Rakefile +2 -2
- data/TODO +3 -1
- data/bin/dtas-archive +1 -1
- data/bin/dtas-console +19 -23
- data/bin/dtas-ctl +1 -1
- data/bin/dtas-cueedit +1 -1
- data/bin/dtas-enq +1 -1
- data/bin/dtas-mlib +1 -1
- data/bin/dtas-msinkctl +1 -1
- data/bin/dtas-partstats +1 -1
- data/bin/dtas-player +1 -1
- data/bin/dtas-readahead +4 -4
- data/bin/dtas-sinkedit +1 -1
- data/bin/dtas-sourceedit +1 -1
- data/bin/dtas-splitfx +8 -1
- data/bin/dtas-tl +1 -1
- data/bin/dtas-xdelay +1 -1
- data/dtas-linux.gemspec +5 -6
- data/dtas-mpris.gemspec +2 -2
- data/dtas.gemspec +2 -2
- data/examples/zsh-completion/README +3 -0
- data/examples/zsh-completion/_dtas-archive +16 -0
- data/examples/zsh-completion/_dtas-ctl +114 -0
- data/examples/zsh-completion/_dtas-cueedit +7 -0
- data/examples/zsh-completion/_dtas-enq +7 -0
- data/examples/zsh-completion/_dtas-mlib +29 -0
- data/examples/zsh-completion/_dtas-msinkctl +8 -0
- data/examples/zsh-completion/_dtas-partstats +7 -0
- data/examples/zsh-completion/_dtas-sinkedit +11 -0
- data/examples/zsh-completion/_dtas-sourceedit +11 -0
- data/examples/zsh-completion/_dtas-splitfx +17 -0
- data/examples/zsh-completion/_dtas-tl +52 -0
- data/examples/zsh-completion/_dtas-xdelay +17 -0
- data/lib/dtas.rb +12 -2
- data/lib/dtas/buffer.rb +10 -5
- data/lib/dtas/buffer/fiddle_splice.rb +216 -0
- data/lib/dtas/buffer/read_write.rb +3 -3
- data/lib/dtas/buffer/splice.rb +16 -10
- data/lib/dtas/command.rb +1 -1
- data/lib/dtas/compat_onenine.rb +1 -1
- data/lib/dtas/cue_index.rb +1 -1
- data/lib/dtas/disclaimer.rb +1 -1
- data/lib/dtas/edit_client.rb +1 -1
- data/lib/dtas/encoding.rb +57 -0
- data/lib/dtas/fadefx.rb +1 -1
- data/lib/dtas/format.rb +1 -1
- data/lib/dtas/mcache.rb +1 -1
- data/lib/dtas/mlib.rb +38 -31
- data/lib/dtas/mlib/migrations/0001_initial.rb +1 -1
- data/lib/dtas/nonblock.rb +1 -1
- data/lib/dtas/parse_freq.rb +1 -1
- data/lib/dtas/parse_time.rb +1 -1
- data/lib/dtas/partstats.rb +1 -1
- data/lib/dtas/pipe.rb +16 -9
- data/lib/dtas/pipeline.rb +75 -0
- data/lib/dtas/player.rb +3 -3
- data/lib/dtas/player/client_handler.rb +23 -15
- data/lib/dtas/process.rb +1 -1
- data/lib/dtas/replaygain.rb +1 -1
- data/lib/dtas/rg_state.rb +1 -1
- data/lib/dtas/serialize.rb +1 -1
- data/lib/dtas/sigevent.rb +6 -3
- data/lib/dtas/sigevent/efd.rb +3 -1
- data/lib/dtas/sigevent/fiddle_efd.rb +38 -0
- data/lib/dtas/sigevent/pipe.rb +2 -2
- data/lib/dtas/sink.rb +1 -1
- data/lib/dtas/source.rb +1 -1
- data/lib/dtas/source/av.rb +1 -1
- data/lib/dtas/source/av_ff_common.rb +1 -1
- data/lib/dtas/source/cmd.rb +1 -1
- data/lib/dtas/source/common.rb +1 -1
- data/lib/dtas/source/ff.rb +1 -1
- data/lib/dtas/source/file.rb +1 -1
- data/lib/dtas/source/mp3gain.rb +1 -1
- data/lib/dtas/source/sox.rb +4 -2
- data/lib/dtas/source/splitfx.rb +1 -1
- data/lib/dtas/spawn_fix.rb +1 -1
- data/lib/dtas/splitfx.rb +6 -3
- data/lib/dtas/state_file.rb +1 -1
- data/lib/dtas/tfx.rb +1 -1
- data/lib/dtas/track.rb +1 -1
- data/lib/dtas/tracklist.rb +1 -1
- data/lib/dtas/unix_accepted.rb +1 -1
- data/lib/dtas/unix_client.rb +1 -1
- data/lib/dtas/unix_server.rb +1 -1
- data/lib/dtas/util.rb +1 -1
- data/lib/dtas/watchable.rb +60 -55
- data/lib/dtas/watchable/fiddle_ino.rb +78 -0
- data/lib/dtas/watchable/inotify.rb +13 -0
- data/lib/dtas/writable_iter.rb +1 -1
- data/lib/dtas/xs.rb +1 -1
- data/perl/dtas-graph +7 -2
- data/setup.rb +1 -2
- data/test/covshow.rb +1 -1
- data/test/helper.rb +1 -1
- data/test/player_integration.rb +1 -1
- data/test/test_buffer.rb +14 -10
- data/test/test_encoding.rb +20 -0
- data/test/test_env.rb +1 -1
- data/test/test_fadefx.rb +1 -1
- data/test/test_format.rb +1 -1
- data/test/test_format_change.rb +1 -1
- data/test/test_mcache.rb +1 -1
- data/test/test_mlib.rb +3 -3
- data/test/test_parse_freq.rb +1 -1
- data/test/test_pipeline.rb +47 -0
- data/test/test_player.rb +1 -1
- data/test/test_player_client_handler.rb +1 -1
- data/test/test_player_integration.rb +1 -1
- data/test/test_process.rb +1 -1
- data/test/test_rg_integration.rb +1 -1
- data/test/test_rg_state.rb +1 -1
- data/test/test_sigevent.rb +20 -0
- data/test/test_sink.rb +1 -1
- data/test/test_sink_pipe_size.rb +13 -16
- data/test/test_sink_tee_integration.rb +1 -1
- data/test/test_source_av.rb +1 -1
- data/test/test_source_sox.rb +1 -1
- data/test/test_splitfx.rb +1 -1
- data/test/test_tfx.rb +1 -1
- data/test/test_tracklist.rb +1 -1
- data/test/test_unixserver.rb +1 -1
- data/test/test_util.rb +1 -1
- metadata +26 -5
data/lib/dtas/player.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
|
2
2
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
3
|
# frozen_string_literal: true
|
4
4
|
require 'yaml'
|
@@ -282,7 +282,7 @@ def sink_death(sink, status)
|
|
282
282
|
if deleted[0]
|
283
283
|
warn("#{sink.name} died unexpectedly: #{status.inspect}")
|
284
284
|
deleted.each { |t| drop_target(t) }
|
285
|
-
|
285
|
+
do_pause unless @targets[0]
|
286
286
|
return # sink stays dead if it died unexpectedly
|
287
287
|
end
|
288
288
|
|
@@ -451,7 +451,7 @@ def __current_drop(src = @current)
|
|
451
451
|
# pull data from sink_buf into @targets, source feeds into sink_buf
|
452
452
|
def sink_iter
|
453
453
|
wait_iter = broadcast_iter(@sink_buf, @targets)
|
454
|
-
|
454
|
+
do_pause if nil == wait_iter # sink error, stop source
|
455
455
|
return wait_iter if @current
|
456
456
|
|
457
457
|
# no source left to feed sink_buf, drain the remaining data
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
|
2
2
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
3
|
# frozen_string_literal: true
|
4
4
|
require_relative '../xs'
|
@@ -197,19 +197,20 @@ def __goto_offset_samples(offset)
|
|
197
197
|
end
|
198
198
|
end
|
199
199
|
|
200
|
+
def __offset_to_i(offset, src)
|
201
|
+
# either "999s" for 999 samples or HH:MM:SS for time
|
202
|
+
offset.sub!(/s\z/, '') ? offset.to_i : src.format.hhmmss_to_samples(offset)
|
203
|
+
end
|
204
|
+
|
200
205
|
def __offset_to_samples(offset)
|
201
|
-
offset
|
202
|
-
@current.format.hhmmss_to_samples(offset)
|
206
|
+
__offset_to_i(offset, @current)
|
203
207
|
end
|
204
208
|
|
205
209
|
# returns seek offset as an Integer in sample count
|
206
|
-
def __seek_offset_adj(dir, offset
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
offset = @current.format.hhmmss_to_samples(offset)
|
211
|
-
end
|
212
|
-
n = __current_decoded_samples + (dir * offset)
|
210
|
+
def __seek_offset_adj(dir, offset,
|
211
|
+
src = @current,
|
212
|
+
current_decoded_samples = __current_decoded_samples)
|
213
|
+
n = current_decoded_samples + (dir * __offset_to_i(offset, src))
|
213
214
|
n = 0 if n < 0
|
214
215
|
"#{n}s"
|
215
216
|
end
|
@@ -391,15 +392,17 @@ def seek_internal(cur, offset)
|
|
391
392
|
end
|
392
393
|
end
|
393
394
|
|
395
|
+
def __offset_direction(offset)
|
396
|
+
offset.sub!(/\A\+/, '') ? 1 : (offset.sub!(/\A-/, '') ? -1 : nil)
|
397
|
+
end
|
398
|
+
|
394
399
|
def dpc_seek(io, msg)
|
395
400
|
offset = msg[0] or return io.emit('ERR usage: seek OFFSET')
|
396
401
|
if @current
|
397
402
|
if @current.respond_to?(:infile)
|
398
403
|
begin
|
399
|
-
if offset
|
400
|
-
offset = __seek_offset_adj(
|
401
|
-
elsif offset.sub!(/\A-/, '')
|
402
|
-
offset = __seek_offset_adj(-1, offset)
|
404
|
+
if direction = __offset_direction(offset)
|
405
|
+
offset = __seek_offset_adj(direction, offset)
|
403
406
|
# else: pass to sox directly
|
404
407
|
end
|
405
408
|
rescue ArgumentError
|
@@ -413,7 +416,12 @@ def dpc_seek(io, msg)
|
|
413
416
|
case file = @queue[0]
|
414
417
|
when String
|
415
418
|
@queue[0] = [ file, offset ]
|
416
|
-
when Array
|
419
|
+
when Array # offset already stored, adjust
|
420
|
+
if direction = __offset_direction(offset)
|
421
|
+
tmp = try_file(*file)
|
422
|
+
cur_off = __offset_to_i(file[1].dup, tmp)
|
423
|
+
offset = __seek_offset_adj(direction, offset, tmp, cur_off)
|
424
|
+
end
|
417
425
|
file[1] = offset
|
418
426
|
else
|
419
427
|
return io.emit("ERR unseekable")
|
data/lib/dtas/process.rb
CHANGED
data/lib/dtas/replaygain.rb
CHANGED
data/lib/dtas/rg_state.rb
CHANGED
data/lib/dtas/serialize.rb
CHANGED
data/lib/dtas/sigevent.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
|
2
2
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
3
|
# frozen_string_literal: true
|
4
4
|
begin
|
5
5
|
raise LoadError, "no eventfd with _DTAS_POSIX" if ENV["_DTAS_POSIX"]
|
6
|
-
|
7
|
-
|
6
|
+
begin
|
7
|
+
require_relative 'sigevent/efd'
|
8
|
+
rescue LoadError
|
9
|
+
require_relative 'sigevent/fiddle_efd'
|
10
|
+
end
|
8
11
|
rescue LoadError
|
9
12
|
require_relative 'sigevent/pipe'
|
10
13
|
end
|
data/lib/dtas/sigevent/efd.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
|
2
2
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
3
|
|
4
4
|
# used in various places for safe wakeups from IO.select via signals
|
5
5
|
# This requires a modern Linux system and the "sleepy_penguin" RubyGem
|
6
|
+
require 'sleepy_penguin'
|
7
|
+
|
6
8
|
class DTAS::Sigevent < SleepyPenguin::EventFD # :nodoc:
|
7
9
|
def self.new
|
8
10
|
super(0, :CLOEXEC)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
|
2
|
+
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
# used in various places for safe wakeups from IO.select via signals
|
6
|
+
# This requires a modern GNU/Linux system with eventfd(2) support
|
7
|
+
require_relative '../nonblock'
|
8
|
+
require 'fiddle'
|
9
|
+
class DTAS::Sigevent # :nodoc:
|
10
|
+
|
11
|
+
EventFD = Fiddle::Function.new(DTAS.libc['eventfd'],
|
12
|
+
[ Fiddle::TYPE_INT, Fiddle::TYPE_INT ], # initval, flags
|
13
|
+
Fiddle::TYPE_INT) # fd
|
14
|
+
|
15
|
+
attr_reader :to_io
|
16
|
+
ONE = [ 1 ].pack('Q').freeze
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
fd = EventFD.call(0, 02000000|00004000) # EFD_CLOEXEC|EFD_NONBLOCK
|
20
|
+
raise "eventfd failed: #{Fiddle.last_error}" if fd < 0
|
21
|
+
@to_io = DTAS::Nonblock.for_fd(fd)
|
22
|
+
@buf = ''.b
|
23
|
+
end
|
24
|
+
|
25
|
+
def signal
|
26
|
+
@to_io.syswrite(ONE)
|
27
|
+
end
|
28
|
+
|
29
|
+
def readable_iter
|
30
|
+
@to_io.read_nonblock(8, @buf, exception: false)
|
31
|
+
yield self, nil # calls DTAS::Process.reaper
|
32
|
+
:wait_readable
|
33
|
+
end
|
34
|
+
|
35
|
+
def close
|
36
|
+
@to_io.close
|
37
|
+
end
|
38
|
+
end
|
data/lib/dtas/sigevent/pipe.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
|
2
2
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
3
|
# frozen_string_literal: true
|
4
4
|
|
5
5
|
# used in various places for safe wakeups from IO.select via signals
|
6
|
-
# A fallback for non-Linux systems lacking the "
|
6
|
+
# A fallback for non-Linux systems lacking the "splice" syscall
|
7
7
|
require_relative '../nonblock'
|
8
8
|
class DTAS::Sigevent # :nodoc:
|
9
9
|
attr_reader :to_io
|
data/lib/dtas/sink.rb
CHANGED
data/lib/dtas/source.rb
CHANGED
data/lib/dtas/source/av.rb
CHANGED
data/lib/dtas/source/cmd.rb
CHANGED
data/lib/dtas/source/common.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
|
2
2
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
3
|
module DTAS::Source::Common # :nodoc:
|
4
4
|
attr_reader :dst_zero_byte # first byte this source object saw
|
data/lib/dtas/source/ff.rb
CHANGED
data/lib/dtas/source/file.rb
CHANGED
data/lib/dtas/source/mp3gain.rb
CHANGED
data/lib/dtas/source/sox.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
|
2
2
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
3
|
# frozen_string_literal: true
|
4
4
|
# encoding: binary
|
@@ -50,17 +50,19 @@ def mcache_lookup(infile)
|
|
50
50
|
out =~ /^Sample Rate\s*:\s*(\d+)/n and dst['rate'] = $1.to_i
|
51
51
|
out =~ /^Precision\s*:\s*(\d+)-bit/n and dst['bits'] = $1.to_i
|
52
52
|
|
53
|
+
enc = Encoding.default_external # typically Encoding::UTF_8
|
53
54
|
if out =~ /\nComments\s*:[ \t]*\n?(.*)\z/mn
|
54
55
|
comments = dst['comments'] = {}
|
55
56
|
key = nil
|
56
57
|
$1.split(/\n/n).each do |line|
|
57
58
|
if line.sub!(/^([^=]+)=/ni, '')
|
58
|
-
key = DTAS.dedupe_str($1.upcase)
|
59
|
+
key = DTAS.dedupe_str(DTAS.try_enc($1.upcase, enc))
|
59
60
|
end
|
60
61
|
(comments[key] ||= ''.b) << "#{line}\n" unless line.empty?
|
61
62
|
end
|
62
63
|
comments.each do |k,v|
|
63
64
|
v.chomp!
|
65
|
+
DTAS.try_enc(v, enc)
|
64
66
|
comments[k] = DTAS.dedupe_str(v)
|
65
67
|
end
|
66
68
|
end
|
data/lib/dtas/source/splitfx.rb
CHANGED
data/lib/dtas/spawn_fix.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
|
2
2
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
3
|
# workaround for older Rubies: https://bugs.ruby-lang.org/issues/8770
|
4
4
|
module DTAS::SpawnFix # :nodoc:
|
data/lib/dtas/splitfx.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
|
2
2
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
3
|
# frozen_string_literal: true
|
4
4
|
require_relative '../dtas'
|
@@ -207,11 +207,11 @@ def splitfx_spawn(target, t, opts)
|
|
207
207
|
env["DITHERFX"] = "dither -s"
|
208
208
|
end
|
209
209
|
comments = Tempfile.new(%W(dtas-splitfx-#{t.comments["TRACKNUMBER"]} .txt))
|
210
|
-
comments.sync = true
|
211
210
|
t.comments.each do |k,v|
|
212
211
|
env[k] = v.to_s
|
213
212
|
comments.puts("#{k}=#{v}")
|
214
213
|
end
|
214
|
+
comments.flush
|
215
215
|
env["COMMENTS"] = "--comment-file=#{comments.path}"
|
216
216
|
infile_env(env, @infile)
|
217
217
|
outarg = outfmt.to_sox_arg
|
@@ -250,7 +250,10 @@ def splitfx_spawn(target, t, opts)
|
|
250
250
|
command = 'true' if opts[:dryrun] # still gotta fork
|
251
251
|
|
252
252
|
# pgroup: false so Ctrl-C on command-line will immediately stop everything
|
253
|
-
|
253
|
+
o = { pgroup: false }
|
254
|
+
e = opts[:err_suffix] and
|
255
|
+
o[:err] = [ "#{env['OUTDIR']}#{env['TRACKNUMBER']}#{e}", 'a' ]
|
256
|
+
[ dtas_spawn(env, command, o), comments ]
|
254
257
|
end
|
255
258
|
|
256
259
|
def load_tracks!(hash)
|
data/lib/dtas/state_file.rb
CHANGED
data/lib/dtas/tfx.rb
CHANGED
data/lib/dtas/track.rb
CHANGED
data/lib/dtas/tracklist.rb
CHANGED
data/lib/dtas/unix_accepted.rb
CHANGED
data/lib/dtas/unix_client.rb
CHANGED
data/lib/dtas/unix_server.rb
CHANGED
data/lib/dtas/util.rb
CHANGED
data/lib/dtas/watchable.rb
CHANGED
@@ -1,67 +1,72 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org>
|
2
2
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
3
|
# frozen_string_literal: true
|
4
|
+
require_relative '../dtas'
|
5
|
+
require_relative 'nonblock'
|
4
6
|
begin
|
5
|
-
|
7
|
+
module DTAS::Watchable # :nodoc:
|
8
|
+
module InotifyCommon # :nodoc:
|
9
|
+
FLAGS = 8 | 128 # IN_CLOSE_WRITE | IN_MOVED_TO
|
6
10
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
w = @watches[event.wd] or next
|
21
|
-
if (event.mask & FLAGS) != 0 && w[event.name]
|
22
|
-
or_call = true
|
11
|
+
def readable_iter
|
12
|
+
or_call = false
|
13
|
+
while event = take(true) # drain the buffer
|
14
|
+
w = @watches[event.wd] or next
|
15
|
+
if (event.mask & FLAGS) != 0 && w[event.name]
|
16
|
+
or_call = true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
if or_call
|
20
|
+
@on_readable.call
|
21
|
+
:delete
|
22
|
+
else
|
23
|
+
:wait_readable
|
23
24
|
end
|
24
25
|
end
|
25
|
-
if or_call
|
26
|
-
@on_readable.call
|
27
|
-
:delete
|
28
|
-
else
|
29
|
-
:wait_readable
|
30
|
-
end
|
31
|
-
end
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
27
|
+
# we must watch the directory, since
|
28
|
+
def watch_files(paths, blk)
|
29
|
+
@watches = {} # wd -> { basename -> true }
|
30
|
+
@on_readable = blk
|
31
|
+
@dir2wd = {}
|
32
|
+
Array(paths).each do |path|
|
33
|
+
watchdir, watchbase = File.split(File.expand_path(path))
|
34
|
+
begin
|
35
|
+
wd = @dir2wd[watchdir] ||= add_watch(watchdir, FLAGS)
|
36
|
+
m = @watches[wd] ||= {}
|
37
|
+
m[watchbase] = true
|
38
|
+
rescue SystemCallError => e
|
39
|
+
warn "#{watchdir.dump}: #{e.message} (#{e.class})"
|
40
|
+
end
|
41
|
+
end
|
43
42
|
end
|
44
|
-
end
|
45
|
-
end
|
43
|
+
end # module InotifyCommon
|
46
44
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
begin
|
46
|
+
require_relative 'watchable/inotify'
|
47
|
+
rescue LoadError
|
48
|
+
# TODO: support kevent
|
49
|
+
require_relative 'watchable/fiddle_ino'
|
50
|
+
end
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
def watch_begin(blk)
|
53
|
+
@ino = DTAS::Watchable::InotifyReadableIter.new
|
54
|
+
@ino.watch_files(@watch_extra << @infile, blk)
|
55
|
+
@ino
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
def watch_end(srv)
|
61
|
-
srv.wait_ctl(@ino, :delete)
|
62
|
-
@ino = @ino.close
|
63
|
-
end
|
64
|
-
end
|
58
|
+
def watch_extra(paths)
|
59
|
+
@ino.watch_extra(paths)
|
60
|
+
end
|
65
61
|
|
66
|
-
|
67
|
-
|
62
|
+
# Closing the inotify descriptor (instead of using inotify_rm_watch)
|
63
|
+
# is cleaner because it avoids EINVAL on race conditions in case
|
64
|
+
# a directory is deleted: https://lkml.org/lkml/2007/7/9/3
|
65
|
+
def watch_end(srv)
|
66
|
+
srv.wait_ctl(@ino, :delete)
|
67
|
+
@ino = @ino.close
|
68
|
+
end
|
69
|
+
end # module DTAS::Watchable
|
70
|
+
rescue LoadError, StandardError => e
|
71
|
+
warn "#{e.message} (#{e.class})"
|
72
|
+
end # begin
|