dtas 0.15.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/GIT-VERSION-GEN +2 -2
- data/INSTALL +7 -9
- data/README +2 -2
- data/Rakefile +2 -2
- data/bin/dtas-console +3 -3
- data/bin/dtas-readahead +2 -2
- data/dtas-linux.gemspec +3 -4
- data/lib/dtas.rb +3 -1
- data/lib/dtas/buffer.rb +4 -2
- data/lib/dtas/buffer/read_write.rb +2 -2
- data/lib/dtas/buffer/splice.rb +12 -10
- data/lib/dtas/encoding.rb +58 -0
- data/lib/dtas/mlib.rb +38 -31
- data/lib/dtas/pipe.rb +9 -6
- data/lib/dtas/pipeline.rb +75 -0
- data/lib/dtas/source/sox.rb +4 -2
- data/lib/dtas/watchable.rb +8 -4
- data/test/test_buffer.rb +14 -10
- data/test/test_encoding.rb +20 -0
- data/test/test_mlib.rb +3 -3
- data/test/test_pipeline.rb +47 -0
- data/test/test_sink_pipe_size.rb +3 -3
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d887afd41dc71abd3448e72c3d33d188e4629b8dbc576af3237c3bd47b246581
|
4
|
+
data.tar.gz: cf5262f4c45becd00e75dc2f1c3de5ab05b27bd9a029c9fef458faec5cc58303
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94f470ad51f9723bf5d3161b445d0434e6e5e45349fc6c5227ecb80aa0c9d1409357979cd8f97edc909bed6c65b75494757b731d2f7cd97f4ed345640465aa7a
|
7
|
+
data.tar.gz: 631dc0a9b16771662bb6f8215ab9ee71acd078ac7cae26f1b90408106da840909d59f99cdf569425b2be05f2c9018f032ad426405ca1bbe1df28af005d2f020c
|
data/GIT-VERSION-GEN
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Copyright (C) 2013-
|
2
|
+
# Copyright (C) 2013-2019 all contributors <dtas-all@nongnu.org>
|
3
3
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
4
4
|
# frozen_string_literal: true
|
5
5
|
CONSTANT = "DTAS::VERSION"
|
6
6
|
RVF = "lib/dtas/version.rb"
|
7
7
|
GVF = "GIT-VERSION-FILE"
|
8
|
-
DEF_VER = "v0.
|
8
|
+
DEF_VER = "v0.16.0"
|
9
9
|
vn = DEF_VER
|
10
10
|
|
11
11
|
# First see if there is a version file (included in release tarballs),
|
data/INSTALL
CHANGED
@@ -19,13 +19,13 @@ Debian 7+ users can install dependencies easily:
|
|
19
19
|
# installing dtas RubyGem on GNU/Linux (Linux kernel 2.6.32+)
|
20
20
|
|
21
21
|
Be sure to have Ruby development headers and a working C compiler.
|
22
|
-
This will pull in the
|
22
|
+
This will pull in the sleepy_penguin RubyGems for minor
|
23
23
|
speedups. If you cannot be bothered to have a development
|
24
24
|
environment, just use "gem install dtas".
|
25
25
|
|
26
26
|
sudo gem install dtas-linux
|
27
27
|
|
28
|
-
This should pull in the "
|
28
|
+
This should pull in the "sleepy_penguin" RubyGems
|
29
29
|
|
30
30
|
For future upgrades of dtas (upgrades to dtas-linux will be infrequent)
|
31
31
|
|
@@ -39,16 +39,14 @@ For future upgrades of dtas (upgrades to dtas-linux will be infrequent)
|
|
39
39
|
|
40
40
|
Grab the latest tarball from our HTTPS site:
|
41
41
|
|
42
|
-
https://80x24.org/dtas/
|
42
|
+
https://80x24.org/dtas/2019/dtas-0.16.0.tar.gz
|
43
43
|
|
44
|
-
$ tar zxvf dtas-0.
|
45
|
-
$ cd dtas-0.
|
44
|
+
$ tar zxvf dtas-0.16.0.tar.gz
|
45
|
+
$ cd dtas-0.16.0
|
46
46
|
$ sudo ruby setup.rb
|
47
47
|
|
48
|
-
GNU/Linux users may optionally install "
|
49
|
-
"sleepy_penguin" packages:
|
48
|
+
GNU/Linux users may optionally install the "sleepy_penguin" package:
|
50
49
|
|
51
|
-
* io_splice - https://bogomips.org/ruby_io_splice/
|
52
50
|
* sleepy_penguin - https://bogomips.org/sleepy_penguin/
|
53
51
|
|
54
52
|
# CONTACT
|
@@ -61,5 +59,5 @@ No subscription is necessary to post to the mailing list.
|
|
61
59
|
|
62
60
|
# COPYRIGHT
|
63
61
|
|
64
|
-
Copyright 2013-
|
62
|
+
Copyright 2013-2019 all contributors <dtas-all@nongnu.org>
|
65
63
|
License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
data/README
CHANGED
@@ -59,7 +59,7 @@ Coming:
|
|
59
59
|
|
60
60
|
## Source code
|
61
61
|
|
62
|
-
git clone
|
62
|
+
git clone https://80x24.org/dtas.git
|
63
63
|
|
64
64
|
Please use git-format-patch(1) and git-send-email(1) distributed with
|
65
65
|
the git(7) suite for generating and sending patches. Please format
|
@@ -86,7 +86,7 @@ Atom: <https://80x24.org/dtas-all/new.atom>
|
|
86
86
|
|
87
87
|
## Copyright
|
88
88
|
|
89
|
-
Copyright 2013-
|
89
|
+
Copyright 2013-2019 all contributors <dtas-all@nongnu.org>\
|
90
90
|
License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
91
91
|
|
92
92
|
dtas is copyrighted Free Software by all contributors, see logs
|
data/Rakefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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 'tempfile'
|
@@ -93,7 +93,7 @@ def tags
|
|
93
93
|
end
|
94
94
|
|
95
95
|
task rsync_docs: %w(NEWS NEWS.atom) do
|
96
|
-
dest = ENV["RSYNC_DEST"] || "80x24.org:/srv/dtas/"
|
96
|
+
dest = ENV["RSYNC_DEST"] || "80x24.org:/srv/80x24/dtas/"
|
97
97
|
top = %w(INSTALL NEWS README COPYING NEWS.atom)
|
98
98
|
files = []
|
99
99
|
|
data/bin/dtas-console
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Copyright (C) 2013-
|
2
|
+
# Copyright (C) 2013-2019 all contributors <dtas-all@nongnu.org>
|
3
3
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
4
4
|
# frozen_string_literal: true
|
5
5
|
#
|
@@ -173,11 +173,11 @@ def may_fail(res, events)
|
|
173
173
|
Curses.setpos(lineno += 1, 0)
|
174
174
|
Curses.clrtoeol
|
175
175
|
Curses.addstr(infile)
|
176
|
-
total = " [#{Time.at(samples / rate).strftime(tfmt)}]" if samples != 0
|
176
|
+
total = " [#{Time.at(samples / rate).utc.strftime(tfmt)}]" if samples != 0
|
177
177
|
Curses.setpos(lineno += 1, 0)
|
178
178
|
Curses.clrtoeol
|
179
179
|
if rate != 0
|
180
|
-
Curses.addstr("#{Time.at(elapsed).strftime(tfmt)}#{total} #{fmt}")
|
180
|
+
Curses.addstr("#{Time.at(elapsed).utc.strftime(tfmt)}#{total} #{fmt}")
|
181
181
|
else
|
182
182
|
Curses.addstr("#{elapsed} samples #{total} #{fmt}")
|
183
183
|
end
|
data/bin/dtas-readahead
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Copyright (C) 2015-
|
2
|
+
# Copyright (C) 2015-2019 all contributors <dtas-all@nongnu.org>
|
3
3
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
4
4
|
# frozen_string_literal: true
|
5
5
|
#
|
@@ -75,7 +75,7 @@ def seek_to_cur_pos(cur_pid, fp)
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def children_of(ppid)
|
78
|
-
`ps h -o pid --ppid=#{ppid}`.split(/\s+/
|
78
|
+
`ps h -o pid --ppid=#{ppid}`.split(/\s+/).map(&:to_i)
|
79
79
|
end
|
80
80
|
|
81
81
|
def expand_pid(pid)
|
data/dtas-linux.gemspec
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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
|
# this just declares dependencies to make gem installation a little easier
|
@@ -13,8 +13,7 @@
|
|
13
13
|
s.email = %q{e@80x24.org}
|
14
14
|
s.files = []
|
15
15
|
s.homepage = 'https://80x24.org/dtas/'
|
16
|
-
s.add_dependency(%q<dtas
|
17
|
-
s.add_dependency(%q<
|
18
|
-
s.add_dependency(%q<sleepy_penguin>, '~> 3')
|
16
|
+
s.add_dependency(%q<dtas>, '~> 0.16')
|
17
|
+
s.add_dependency(%q<sleepy_penguin>, '~> 3.5')
|
19
18
|
s.licenses = 'GPL-3.0+'
|
20
19
|
end
|
data/lib/dtas.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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
|
|
@@ -42,3 +42,5 @@ def self.dedupe_str(str)
|
|
42
42
|
|
43
43
|
require_relative 'dtas/compat_onenine'
|
44
44
|
require_relative 'dtas/spawn_fix'
|
45
|
+
require_relative 'dtas/encoding'
|
46
|
+
DTAS.extend(DTAS::Encoding)
|
data/lib/dtas/buffer.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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 'io/wait'
|
@@ -8,7 +8,9 @@
|
|
8
8
|
class DTAS::Buffer # :nodoc:
|
9
9
|
begin
|
10
10
|
raise LoadError, "no splice with _DTAS_POSIX" if ENV["_DTAS_POSIX"]
|
11
|
-
require '
|
11
|
+
require 'sleepy_penguin' # splice is only in Linux for now...
|
12
|
+
SleepyPenguin.respond_to?(:splice) or
|
13
|
+
raise LoadError, 'sleepy_penguin 3.5+ required for splice', []
|
12
14
|
require_relative 'buffer/splice'
|
13
15
|
include DTAS::Buffer::Splice
|
14
16
|
rescue LoadError
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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 'io/nonblock'
|
@@ -7,7 +7,7 @@
|
|
7
7
|
require_relative '../nonblock'
|
8
8
|
|
9
9
|
# compatibility code for systems lacking "splice" support via the
|
10
|
-
# "
|
10
|
+
# "sleepy_penguin" 3.5+ RubyGem. Used only by -player
|
11
11
|
module DTAS::Buffer::ReadWrite # :nodoc:
|
12
12
|
MAX_AT_ONCE = 512 # min PIPE_BUF value in POSIX
|
13
13
|
attr_accessor :buffer_size
|
data/lib/dtas/buffer/splice.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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 'io/nonblock'
|
5
|
-
require '
|
5
|
+
require 'sleepy_penguin'
|
6
6
|
require_relative '../../dtas'
|
7
7
|
require_relative '../pipe'
|
8
8
|
|
9
|
-
# Used by -player on Linux systems with the "
|
9
|
+
# Used by -player on Linux systems with the "sleepy_penguin" RubyGem installed
|
10
10
|
module DTAS::Buffer::Splice # :nodoc:
|
11
11
|
MAX_AT_ONCE = 4096 # page size in Linux
|
12
12
|
MAX_AT_ONCE_1 = 65536
|
13
|
-
F_MOVE =
|
13
|
+
F_MOVE = SleepyPenguin::F_MOVE
|
14
|
+
F_NONBLOCK = SleepyPenguin::F_NONBLOCK
|
15
|
+
TRY = { exception: false }.freeze
|
14
16
|
|
15
17
|
def buffer_size
|
16
18
|
@to_io.pipe_size
|
@@ -24,13 +26,13 @@ def buffer_size=(bytes)
|
|
24
26
|
|
25
27
|
# be sure to only call this with nil when all writers to @wr are done
|
26
28
|
def discard(bytes)
|
27
|
-
|
29
|
+
SleepyPenguin.splice(@to_io, DTAS.null, bytes)
|
28
30
|
end
|
29
31
|
|
30
32
|
def broadcast_one(targets, limit = nil)
|
31
33
|
# single output is always non-blocking
|
32
34
|
limit ||= MAX_AT_ONCE_1
|
33
|
-
s =
|
35
|
+
s = SleepyPenguin.splice(@to_io, targets[0], limit, F_MOVE, TRY)
|
34
36
|
if Symbol === s
|
35
37
|
targets # our one and only target blocked on write
|
36
38
|
else
|
@@ -46,7 +48,7 @@ def broadcast_one(targets, limit = nil)
|
|
46
48
|
def __tee_in_full(src, dst, bytes)
|
47
49
|
rv = 0
|
48
50
|
while bytes > 0
|
49
|
-
s =
|
51
|
+
s = SleepyPenguin.tee(src, dst, bytes)
|
50
52
|
bytes -= s
|
51
53
|
rv += s
|
52
54
|
end
|
@@ -56,7 +58,7 @@ def __tee_in_full(src, dst, bytes)
|
|
56
58
|
def __splice_in_full(src, dst, bytes, flags)
|
57
59
|
rv = 0
|
58
60
|
while bytes > 0
|
59
|
-
s =
|
61
|
+
s = SleepyPenguin.splice(src, dst, bytes, flags)
|
60
62
|
rv += s
|
61
63
|
bytes -= s
|
62
64
|
end
|
@@ -69,7 +71,7 @@ def __broadcast_tee(blocked, targets, chunk_size)
|
|
69
71
|
targets.delete_if do |dst|
|
70
72
|
begin
|
71
73
|
t = (dst.nonblock? || most_teed == 0) ?
|
72
|
-
|
74
|
+
SleepyPenguin.tee(@to_io, dst, chunk_size, F_NONBLOCK, TRY) :
|
73
75
|
__tee_in_full(@to_io, dst, chunk_size)
|
74
76
|
if Integer === t
|
75
77
|
if t > most_teed
|
@@ -117,7 +119,7 @@ def broadcast_inf(targets, limit = nil)
|
|
117
119
|
begin
|
118
120
|
targets << last
|
119
121
|
if last.nonblock? || most_teed == 0
|
120
|
-
s =
|
122
|
+
s = SleepyPenguin.splice(@to_io, last, bytes, F_MOVE|F_NONBLOCK, TRY)
|
121
123
|
if Symbol === s
|
122
124
|
blocked << last
|
123
125
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Copyright (C) 2018-2019 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
|
+
# This module gets included in DTAS
|
6
|
+
module DTAS::Encoding # :nodoc:
|
7
|
+
def self.extended(mod)
|
8
|
+
mod.instance_eval { @charlock_holmes = nil}
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def try_enc_harder(str, enc, old) # :nodoc:
|
14
|
+
case @charlock_holmes
|
15
|
+
when nil
|
16
|
+
begin
|
17
|
+
require 'charlock_holmes'
|
18
|
+
@charlock_holmes = CharlockHolmes::EncodingDetector.new
|
19
|
+
rescue LoadError
|
20
|
+
warn "`charlock_holmes` gem not available for encoding detection"
|
21
|
+
@charlock_holmes = false
|
22
|
+
end
|
23
|
+
when false
|
24
|
+
enc_fallback(str, enc, old)
|
25
|
+
else
|
26
|
+
res = @charlock_holmes.detect(str)
|
27
|
+
if det = res[:ruby_encoding]
|
28
|
+
str.force_encoding(det)
|
29
|
+
warn "charlock_holmes detected #{str.inspect} as #{det}..."
|
30
|
+
str.valid_encoding? or enc_fallback(str, det, old)
|
31
|
+
else
|
32
|
+
enc_fallback(str, enc, old)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
str
|
36
|
+
end
|
37
|
+
|
38
|
+
def enc_fallback(str, enc, old) # :nodoc:
|
39
|
+
str.force_encoding(old)
|
40
|
+
warn "could not detect encoding for #{str.inspect} (not #{enc})"
|
41
|
+
end
|
42
|
+
|
43
|
+
public
|
44
|
+
|
45
|
+
def try_enc(str, enc, harder = true) # :nodoc:
|
46
|
+
old = str.encoding
|
47
|
+
return str if old == enc
|
48
|
+
str.force_encoding(enc)
|
49
|
+
unless str.valid_encoding?
|
50
|
+
if harder
|
51
|
+
try_enc_harder(str, enc, old)
|
52
|
+
else
|
53
|
+
enc_fallback(str, enc, old)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
str
|
57
|
+
end
|
58
|
+
end
|
data/lib/dtas/mlib.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# Copyright (C) 2015-
|
2
|
+
# Copyright (C) 2015-2019 all contributors <dtas-all@nongnu.org>
|
3
3
|
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
4
4
|
# frozen_string_literal: true
|
5
5
|
#
|
@@ -10,6 +10,7 @@
|
|
10
10
|
require_relative 'source/ff'
|
11
11
|
require_relative 'source/splitfx'
|
12
12
|
require 'socket'
|
13
|
+
require 'tempfile'
|
13
14
|
|
14
15
|
# For the DTAS Music Library, based on what MPD uses.
|
15
16
|
class DTAS::Mlib # :nodoc:
|
@@ -37,16 +38,13 @@ class DTAS::Mlib # :nodoc:
|
|
37
38
|
|
38
39
|
def initialize(db)
|
39
40
|
if String === db
|
41
|
+
require 'sequel'
|
42
|
+
opts = { single_threaded: true }
|
40
43
|
db = "sqlite://#{db}" unless db.include?('://')
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
db.transaction_mode = :immediate
|
46
|
-
db.synchronous = :off
|
47
|
-
db.case_sensitive_like = false
|
48
|
-
else
|
49
|
-
warn 'non-SQLite databases may not work in the future'
|
44
|
+
opts[:transaction_mode] = :immediate
|
45
|
+
opts[:synchronous] = :off
|
46
|
+
opts[:case_sensitive_like] = false # only for 'search'
|
47
|
+
db = Sequel.connect(db, opts)
|
50
48
|
end
|
51
49
|
@db = db
|
52
50
|
@pwd = nil
|
@@ -65,15 +63,23 @@ def initialize(db)
|
|
65
63
|
]
|
66
64
|
end
|
67
65
|
|
66
|
+
def synchronize
|
67
|
+
@lock.flock(File::LOCK_EX)
|
68
|
+
@db.transaction { yield }
|
69
|
+
ensure
|
70
|
+
@lock.flock(File::LOCK_UN)
|
71
|
+
end
|
72
|
+
|
68
73
|
def init_suffixes
|
69
|
-
`sox --help 2>/dev/null` =~ /\nAUDIO FILE FORMATS:\s*([^\n]+)/
|
74
|
+
`sox --help 2>/dev/null` =~ /\nAUDIO FILE FORMATS:\s*([^\n]+)/
|
70
75
|
re = $1.split(/\s+/).map! { |x| Regexp.quote(x) }.join('|')
|
71
76
|
@suffixes = Regexp.new("\\.(?:#{re}|yml)\\z", Regexp::IGNORECASE)
|
72
77
|
end
|
73
78
|
|
74
|
-
def worker(todo)
|
79
|
+
def worker(todo, lock)
|
80
|
+
@lock = lock
|
75
81
|
@work.close
|
76
|
-
@db.tables # reconnect before chdir
|
82
|
+
synchronize { @db.tables } # reconnect before chdir
|
77
83
|
@pwd = Dir.pwd.b
|
78
84
|
begin
|
79
85
|
buf = todo.recv(16384) # 4x bigger than PATH_MAX ought to be enough
|
@@ -87,7 +93,7 @@ def worker(todo)
|
|
87
93
|
end
|
88
94
|
|
89
95
|
def ignore(job)
|
90
|
-
|
96
|
+
synchronize do
|
91
97
|
node_ensure(job.parent_id, job.path, DM_IGN, job.ctime)
|
92
98
|
end
|
93
99
|
end
|
@@ -106,24 +112,16 @@ def worker_work(job)
|
|
106
112
|
end
|
107
113
|
return ignore(job) unless found
|
108
114
|
tlen = found.duration
|
109
|
-
return ignore(job) if tlen < 0
|
115
|
+
return ignore(job) if tlen.nil? || tlen < 0
|
110
116
|
tlen = tlen.round
|
111
117
|
tmp = {}
|
112
|
-
found.comments
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
# FIXME: this fallback needs testing
|
117
|
-
[ Encoding::UTF_8, Encoding::ISO_8859_1 ].each do |enc|
|
118
|
-
value.force_encoding(enc)
|
119
|
-
if value.valid_encoding?
|
120
|
-
value.encode!(Encoding::UTF_8) if enc != Encoding::UTF_8
|
121
|
-
tmp[tag_id] = value
|
122
|
-
break
|
123
|
-
end
|
118
|
+
if comments = found.comments
|
119
|
+
comments.each do |tag, value|
|
120
|
+
tag_id = @tag_map[tag] or next
|
121
|
+
tmp[tag_id] = value if value.valid_encoding?
|
124
122
|
end
|
125
123
|
end
|
126
|
-
|
124
|
+
synchronize do
|
127
125
|
node_id = node_ensure(job.parent_id, path, tlen, job.ctime)[:id]
|
128
126
|
vals = @db[:vals]
|
129
127
|
comments = @db[:comments]
|
@@ -154,11 +152,20 @@ def update(path, opts = nil)
|
|
154
152
|
@work and raise 'update already running'
|
155
153
|
todo, @work = UNIXSocket.pair(:SOCK_SEQPACKET)
|
156
154
|
@db.disconnect
|
157
|
-
|
155
|
+
|
156
|
+
# like a Mutex between processes
|
157
|
+
@lock = Tempfile.new('dtas.mlib.lock')
|
158
|
+
jobs.times do |i|
|
159
|
+
lock = File.open(@lock.path, 'w')
|
160
|
+
fork { worker(todo, lock) }
|
161
|
+
lock.close
|
162
|
+
end
|
163
|
+
@lock.unlink
|
158
164
|
todo.close
|
159
165
|
scan_dir(path, st)
|
160
166
|
@work.close
|
161
167
|
Process.waitall
|
168
|
+
@lock.close
|
162
169
|
ensure
|
163
170
|
@work = nil
|
164
171
|
end
|
@@ -246,7 +253,7 @@ def root_node
|
|
246
253
|
end
|
247
254
|
|
248
255
|
def dir_vivify(parts, ctime)
|
249
|
-
|
256
|
+
synchronize do
|
250
257
|
dir = root_node
|
251
258
|
last = parts.pop
|
252
259
|
parts.each do |name|
|
@@ -300,7 +307,7 @@ def scan_dir(path, st, parent_id = nil)
|
|
300
307
|
dir = dir_vivify(@pwd.split(%r{/+}n), st.ctime.to_i)
|
301
308
|
dir_id = dir[:id]
|
302
309
|
|
303
|
-
|
310
|
+
synchronize do
|
304
311
|
@db[:nodes].where(parent_id: dir_id).each do |node|
|
305
312
|
File.exist?(node[:name]) or remove_entry(node)
|
306
313
|
end
|
data/lib/dtas/pipe.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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
|
-
require '
|
5
|
+
require 'sleepy_penguin'
|
6
6
|
rescue LoadError
|
7
7
|
end
|
8
8
|
require_relative '../dtas'
|
@@ -20,12 +20,15 @@ def self.new
|
|
20
20
|
rv
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
23
|
+
def pipe_size=(nr)
|
24
|
+
defined?(SleepyPenguin::F_SETPIPE_SZ) and
|
25
|
+
fcntl(SleepyPenguin::F_SETPIPE_SZ, nr)
|
27
26
|
end
|
28
27
|
|
28
|
+
def pipe_size
|
29
|
+
fcntl(SleepyPenguin::F_GETPIPE_SZ)
|
30
|
+
end if defined?(SleepyPenguin::F_GETPIPE_SZ)
|
31
|
+
|
29
32
|
# avoid syscall, we never change IO#nonblock= directly
|
30
33
|
def nonblock?
|
31
34
|
false
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Copyright (C) 2017-2019 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
|
+
require_relative '../dtas'
|
5
|
+
require_relative 'spawn_fix'
|
6
|
+
|
7
|
+
module DTAS::Pipeline # :nodoc:
|
8
|
+
include DTAS::SpawnFix
|
9
|
+
|
10
|
+
# Process.spawn wrapper which supports running Proc-like objects in
|
11
|
+
# a separate process, not just external commands.
|
12
|
+
# Returns the pid of the spawned process
|
13
|
+
def pspawn(env, cmd, rdr = {})
|
14
|
+
case cmd
|
15
|
+
when Array
|
16
|
+
spawn(env, *cmd, rdr)
|
17
|
+
else # support running Proc-like objects, too:
|
18
|
+
fork do
|
19
|
+
ENV.update(env) if env
|
20
|
+
|
21
|
+
# setup redirects
|
22
|
+
[ $stdin, $stdout, $stderr ].each_with_index do |io, fd|
|
23
|
+
dst = rdr[fd] and io.reopen(dst)
|
24
|
+
end
|
25
|
+
|
26
|
+
# close all other pipes, since we can't rely on FD_CLOEXEC
|
27
|
+
# (as we do not exec, here)
|
28
|
+
rdr.each do |k, v|
|
29
|
+
k.close if v == :close
|
30
|
+
end
|
31
|
+
cmd.call
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# +pipeline+ is an Array of (Arrays or Procs)
|
37
|
+
def run_pipeline(env, pipeline)
|
38
|
+
pids = {} # pid => pipeline index
|
39
|
+
work = pipeline.dup
|
40
|
+
last = work.pop
|
41
|
+
nr = work.size
|
42
|
+
rdr = {} # redirect mapping for Process.spawn
|
43
|
+
|
44
|
+
# we need to make sure pipes are closed in any forked processes
|
45
|
+
# (they are redirected to stdin or stdout, first)
|
46
|
+
pipes = nr.times.map { IO.pipe.each { |io| rdr[io] = :close } }
|
47
|
+
|
48
|
+
# start the first and last commands first, they only have one pipe, each
|
49
|
+
last_pid = pspawn(env, last, rdr.merge(0 => pipes[-1][0]))
|
50
|
+
pids[last_pid] = nr
|
51
|
+
first = work.shift
|
52
|
+
first_pid = pspawn(env, first, rdr.merge(1 => pipes[0][1]))
|
53
|
+
pids[first_pid] = 0
|
54
|
+
|
55
|
+
# start the middle commands, they both have two pipes:
|
56
|
+
work.each_with_index do |cmd, i|
|
57
|
+
pid = pspawn(env, cmd, rdr.merge(0 => pipes[i][0], 1 => pipes[i+1][1]))
|
58
|
+
pids[pid] = i + 1
|
59
|
+
end
|
60
|
+
|
61
|
+
# all pipes handed off to children, close so they see EOF
|
62
|
+
pipes.flatten!.each(&:close).clear
|
63
|
+
|
64
|
+
# wait for children to finish
|
65
|
+
fails = []
|
66
|
+
until pids.empty?
|
67
|
+
pid, status = Process.waitpid2(-1)
|
68
|
+
nr = pids.delete(pid)
|
69
|
+
status.success? or
|
70
|
+
fails << "reaped #{nr} #{pipeline[nr].inspect} #{status.inspect}"
|
71
|
+
end
|
72
|
+
# behave like "set -o pipefail" in bash
|
73
|
+
raise fails.join("\n") if fails[0]
|
74
|
+
end
|
75
|
+
end
|
data/lib/dtas/source/sox.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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/watchable.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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
|
@@ -37,9 +37,13 @@ def watch_files(paths, blk)
|
|
37
37
|
@dir2wd = {}
|
38
38
|
Array(paths).each do |path|
|
39
39
|
watchdir, watchbase = File.split(File.expand_path(path))
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
begin
|
41
|
+
wd = @dir2wd[watchdir] ||= add_watch(watchdir, FLAGS)
|
42
|
+
m = @watches[wd] ||= {}
|
43
|
+
m[watchbase] = true
|
44
|
+
rescue SystemCallError => e
|
45
|
+
warn "#{watchdir.dump}: #{e.message} (#{e.class})"
|
46
|
+
end
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
data/test/test_buffer.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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 './test/helper'
|
@@ -49,14 +49,14 @@ def test_set_buffer_size
|
|
49
49
|
buf = new_buffer
|
50
50
|
buf.buffer_size = @@max_size
|
51
51
|
assert_equal @@max_size, buf.buffer_size
|
52
|
-
end if
|
52
|
+
end if defined?(SleepyPenguin::F_GETPIPE_SZ)
|
53
53
|
|
54
54
|
def test_buffer_size
|
55
55
|
buf = new_buffer
|
56
56
|
assert_operator buf.buffer_size, :>, 128
|
57
57
|
buf.buffer_size = @@max_size
|
58
58
|
assert_equal @@max_size, buf.buffer_size
|
59
|
-
end if
|
59
|
+
end if defined?(SleepyPenguin::F_GETPIPE_SZ)
|
60
60
|
|
61
61
|
def test_broadcast_1
|
62
62
|
buf = new_buffer
|
@@ -87,9 +87,9 @@ def test_broadcast_tee
|
|
87
87
|
assert_empty blocked
|
88
88
|
assert_equal "HELLO", a[0].read(5)
|
89
89
|
assert_equal "HELLO", b[0].read(5)
|
90
|
-
max = '*' * a[0]
|
90
|
+
max = '*' * pipe_size(a[0])
|
91
91
|
assert_equal max.size, a[1].write(max)
|
92
|
-
assert_equal a[0].nread, a[0]
|
92
|
+
assert_equal a[0].nread, pipe_size(a[0])
|
93
93
|
a[1].nonblock = true
|
94
94
|
assert_equal 5, buf.__broadcast_tee(blocked, [a[1], b[1]], 5)
|
95
95
|
assert_equal [a[1]], blocked
|
@@ -108,10 +108,10 @@ def test_broadcast
|
|
108
108
|
assert_equal "HELLO", a[0].read(5)
|
109
109
|
assert_equal "HELLO", b[0].read(5)
|
110
110
|
|
111
|
-
return unless
|
111
|
+
return unless defined?(SleepyPenguin::F_GETPIPE_SZ)
|
112
112
|
|
113
113
|
b[1].nonblock = true
|
114
|
-
b[1].write('*' * b[1]
|
114
|
+
b[1].write('*' * pipe_size(b[1]))
|
115
115
|
buf.wr.write "BYE"
|
116
116
|
assert_equal :wait_readable, buf.broadcast([a[1], b[1]])
|
117
117
|
assert_equal 8, buf.bytes_xfer
|
@@ -157,8 +157,8 @@ def test_broadcast_all_full
|
|
157
157
|
a = pipe
|
158
158
|
b = pipe
|
159
159
|
buf = new_buffer
|
160
|
-
a[1].write('*' * a[1]
|
161
|
-
b[1].write('*' * b[1]
|
160
|
+
a[1].write('*' * pipe_size(a[1]))
|
161
|
+
b[1].write('*' * pipe_size(b[1]))
|
162
162
|
|
163
163
|
a[1].nonblock = true
|
164
164
|
b[1].nonblock = true
|
@@ -167,7 +167,7 @@ def test_broadcast_all_full
|
|
167
167
|
buf.wr.write "HELLO"
|
168
168
|
assert_equal tmp, buf.broadcast(tmp)
|
169
169
|
assert_equal [a[1], b[1]], tmp
|
170
|
-
end if
|
170
|
+
end if defined?(SleepyPenguin::F_GETPIPE_SZ)
|
171
171
|
|
172
172
|
def test_serialize
|
173
173
|
buf = new_buffer
|
@@ -204,4 +204,8 @@ def test_load_size
|
|
204
204
|
assert_equal 4096, buf.buffer_size
|
205
205
|
buf.close!
|
206
206
|
end
|
207
|
+
|
208
|
+
def pipe_size(io)
|
209
|
+
io.fcntl(SleepyPenguin::F_GETPIPE_SZ)
|
210
|
+
end
|
207
211
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright (C) 2018-2019 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
|
+
require './test/helper'
|
5
|
+
require 'dtas'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
class TestEncoding < Testcase
|
9
|
+
def test_encoding
|
10
|
+
data = <<EOD # <20180111114546.77906b35@cumparsita.ch>
|
11
|
+
---
|
12
|
+
comments:
|
13
|
+
ARTIST: !binary |-
|
14
|
+
RW5yaXF1ZSBSb2Ryw61ndWV6
|
15
|
+
EOD
|
16
|
+
hash = YAML.load(data)
|
17
|
+
artist = DTAS.try_enc(hash['comments']['ARTIST'], Encoding::UTF_8)
|
18
|
+
assert_equal 'Enrique Rodríguez', artist
|
19
|
+
end
|
20
|
+
end
|
data/test/test_mlib.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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 'helper'
|
5
5
|
begin
|
6
6
|
require 'dtas/mlib'
|
7
|
-
require 'sequel
|
7
|
+
require 'sequel'
|
8
8
|
require 'sqlite3'
|
9
9
|
rescue LoadError => err
|
10
10
|
warn "skipping mlib test: #{err.message}"
|
@@ -13,7 +13,7 @@
|
|
13
13
|
|
14
14
|
class TestMlib < Testcase
|
15
15
|
def setup
|
16
|
-
@db = Sequel.sqlite(':memory:')
|
16
|
+
@db = Sequel.sqlite(':memory:', case_sensitive_like: false)
|
17
17
|
end
|
18
18
|
|
19
19
|
def test_migrate
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Copyright (C) 2017-2019 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
|
+
require './test/helper'
|
5
|
+
require 'dtas/pipeline'
|
6
|
+
|
7
|
+
class TestPipeline < Testcase
|
8
|
+
include DTAS::Pipeline
|
9
|
+
def setup
|
10
|
+
@env = ENV.to_hash
|
11
|
+
end
|
12
|
+
|
13
|
+
def pipeline_result
|
14
|
+
IO.pipe do |rd, wr|
|
15
|
+
begin
|
16
|
+
pid = fork do
|
17
|
+
rd.close
|
18
|
+
$stdout.reopen(wr)
|
19
|
+
yield
|
20
|
+
exit!(0)
|
21
|
+
end
|
22
|
+
wr.close
|
23
|
+
return rd.read
|
24
|
+
ensure
|
25
|
+
_, status = Process.waitpid2(pid)
|
26
|
+
assert_predicate status, :success?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_pipeline
|
33
|
+
assert_equal("BYYRU\n", pipeline_result do
|
34
|
+
run_pipeline(@env, [
|
35
|
+
%w(echo hello), # anything which generates something to stdout
|
36
|
+
%w(tr [a-z] [A-Z]), # upcase
|
37
|
+
# this lambda runs inside its own process
|
38
|
+
lambda do
|
39
|
+
$stdin.each_line { |l| $stdout.write("#{l.chomp.reverse}\n") }
|
40
|
+
exit!(0)
|
41
|
+
end,
|
42
|
+
# rot13
|
43
|
+
%w(tr [a-m][n-z][A-M][N-Z] [n-z][a-m][N-Z][A-M])
|
44
|
+
])
|
45
|
+
end)
|
46
|
+
end
|
47
|
+
end
|
data/test/test_sink_pipe_size.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
# Copyright (C) 2013-
|
1
|
+
# Copyright (C) 2013-2019 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
|
-
require '
|
5
|
+
require 'sleepy_penguin'
|
6
6
|
require './test/player_integration'
|
7
7
|
class TestSinkPipeSizeIntegration < Testcase
|
8
8
|
include PlayerIntegration
|
@@ -14,7 +14,7 @@ def test_sink_pipe_size_integration
|
|
14
14
|
s.req_ok("sink ed default pipe_size=0x10000")
|
15
15
|
s.req_ok("sink ed default pipe_size=")
|
16
16
|
s.req_ok("sink ed default pipe_size=4096")
|
17
|
-
end if
|
17
|
+
end if SleepyPenguin.const_defined?(:F_SETPIPE_SZ)
|
18
18
|
end
|
19
19
|
rescue LoadError
|
20
20
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dtas
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dtas hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |-
|
14
14
|
Free Software command-line tools for audio playback, mastering, and
|
@@ -98,6 +98,7 @@ files:
|
|
98
98
|
- lib/dtas/cue_index.rb
|
99
99
|
- lib/dtas/disclaimer.rb
|
100
100
|
- lib/dtas/edit_client.rb
|
101
|
+
- lib/dtas/encoding.rb
|
101
102
|
- lib/dtas/fadefx.rb
|
102
103
|
- lib/dtas/format.rb
|
103
104
|
- lib/dtas/mcache.rb
|
@@ -108,6 +109,7 @@ files:
|
|
108
109
|
- lib/dtas/parse_time.rb
|
109
110
|
- lib/dtas/partstats.rb
|
110
111
|
- lib/dtas/pipe.rb
|
112
|
+
- lib/dtas/pipeline.rb
|
111
113
|
- lib/dtas/player.rb
|
112
114
|
- lib/dtas/player/client_handler.rb
|
113
115
|
- lib/dtas/process.rb
|
@@ -164,6 +166,7 @@ files:
|
|
164
166
|
- test/helper.rb
|
165
167
|
- test/player_integration.rb
|
166
168
|
- test/test_buffer.rb
|
169
|
+
- test/test_encoding.rb
|
167
170
|
- test/test_env.rb
|
168
171
|
- test/test_fadefx.rb
|
169
172
|
- test/test_format.rb
|
@@ -171,6 +174,7 @@ files:
|
|
171
174
|
- test/test_mcache.rb
|
172
175
|
- test/test_mlib.rb
|
173
176
|
- test/test_parse_freq.rb
|
177
|
+
- test/test_pipeline.rb
|
174
178
|
- test/test_player.rb
|
175
179
|
- test/test_player_client_handler.rb
|
176
180
|
- test/test_player_integration.rb
|
@@ -206,8 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
206
210
|
- !ruby/object:Gem::Version
|
207
211
|
version: '0'
|
208
212
|
requirements: []
|
209
|
-
|
210
|
-
rubygems_version: 2.6.10
|
213
|
+
rubygems_version: 3.0.1
|
211
214
|
signing_key:
|
212
215
|
specification_version: 4
|
213
216
|
summary: duct tape audio suite for *nix
|