dtas 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/.gitignore +9 -0
- data/.rsync_doc +3 -0
- data/COPYING +674 -0
- data/Documentation/.gitignore +3 -0
- data/Documentation/GNUmakefile +46 -0
- data/Documentation/dtas-console.txt +42 -0
- data/Documentation/dtas-ctl.txt +64 -0
- data/Documentation/dtas-cueedit.txt +24 -0
- data/Documentation/dtas-enq.txt +29 -0
- data/Documentation/dtas-msinkctl.txt +45 -0
- data/Documentation/dtas-player.txt +110 -0
- data/Documentation/dtas-player_effects.txt +45 -0
- data/Documentation/dtas-player_protocol.txt +181 -0
- data/Documentation/dtas-sinkedit.txt +41 -0
- data/Documentation/dtas-sourceedit.txt +33 -0
- data/Documentation/dtas-xdelay.txt +57 -0
- data/Documentation/troubleshooting.txt +13 -0
- data/GIT-VERSION-GEN +30 -0
- data/GNUmakefile +9 -0
- data/HACKING +12 -0
- data/INSTALL +53 -0
- data/README +103 -0
- data/Rakefile +97 -0
- data/TODO +4 -0
- data/bin/dtas-console +160 -0
- data/bin/dtas-ctl +10 -0
- data/bin/dtas-cueedit +78 -0
- data/bin/dtas-enq +13 -0
- data/bin/dtas-msinkctl +51 -0
- data/bin/dtas-player +34 -0
- data/bin/dtas-sinkedit +58 -0
- data/bin/dtas-sourceedit +48 -0
- data/bin/dtas-xdelay +85 -0
- data/dtas-linux.gemspec +18 -0
- data/dtas-mpris.gemspec +16 -0
- data/examples/dtas_state.yml +18 -0
- data/lib/dtas.rb +7 -0
- data/lib/dtas/buffer.rb +90 -0
- data/lib/dtas/buffer/read_write.rb +102 -0
- data/lib/dtas/buffer/splice.rb +142 -0
- data/lib/dtas/command.rb +43 -0
- data/lib/dtas/compat_onenine.rb +18 -0
- data/lib/dtas/disclaimer.rb +18 -0
- data/lib/dtas/format.rb +151 -0
- data/lib/dtas/pipe.rb +39 -0
- data/lib/dtas/player.rb +393 -0
- data/lib/dtas/player/client_handler.rb +463 -0
- data/lib/dtas/process.rb +87 -0
- data/lib/dtas/replaygain.rb +41 -0
- data/lib/dtas/rg_state.rb +99 -0
- data/lib/dtas/serialize.rb +9 -0
- data/lib/dtas/sigevent.rb +10 -0
- data/lib/dtas/sigevent/efd.rb +20 -0
- data/lib/dtas/sigevent/pipe.rb +28 -0
- data/lib/dtas/sink.rb +121 -0
- data/lib/dtas/source.rb +147 -0
- data/lib/dtas/source/command.rb +40 -0
- data/lib/dtas/source/common.rb +14 -0
- data/lib/dtas/source/mp3.rb +37 -0
- data/lib/dtas/state_file.rb +33 -0
- data/lib/dtas/unix_accepted.rb +76 -0
- data/lib/dtas/unix_client.rb +51 -0
- data/lib/dtas/unix_server.rb +110 -0
- data/lib/dtas/util.rb +15 -0
- data/lib/dtas/writable_iter.rb +22 -0
- data/perl/dtas-graph +129 -0
- data/pkg.mk +26 -0
- data/setup.rb +1586 -0
- data/test/covshow.rb +30 -0
- data/test/helper.rb +76 -0
- data/test/player_integration.rb +121 -0
- data/test/test_buffer.rb +216 -0
- data/test/test_format.rb +61 -0
- data/test/test_format_change.rb +49 -0
- data/test/test_player.rb +47 -0
- data/test/test_player_client_handler.rb +86 -0
- data/test/test_player_integration.rb +220 -0
- data/test/test_rg_integration.rb +117 -0
- data/test/test_rg_state.rb +32 -0
- data/test/test_sink.rb +32 -0
- data/test/test_sink_tee_integration.rb +34 -0
- data/test/test_source.rb +102 -0
- data/test/test_unixserver.rb +66 -0
- data/test/test_util.rb +15 -0
- metadata +208 -0
data/TODO
ADDED
data/bin/dtas-console
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
4
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
5
|
+
#
|
6
|
+
# Note: no idea what I'm doing, especially w.r.t. curses
|
7
|
+
require 'dtas/unix_client'
|
8
|
+
require 'curses'
|
9
|
+
require 'yaml'
|
10
|
+
|
11
|
+
w = DTAS::UNIXClient.new
|
12
|
+
w.req_ok('watch')
|
13
|
+
c = DTAS::UNIXClient.new
|
14
|
+
cur = YAML.load(c.req('current'))
|
15
|
+
readable = [ w, $stdin ]
|
16
|
+
|
17
|
+
def update_tfmt(prec)
|
18
|
+
prec == 0 ? '%H:%M:%S' : "%H:%M:%S.%#{prec}N"
|
19
|
+
end
|
20
|
+
trap(:INT) { exit(0) }
|
21
|
+
trap(:TERM) { exit(0) }
|
22
|
+
|
23
|
+
# time precision
|
24
|
+
prec_nr = 1
|
25
|
+
prec_step = (0..9).to_a
|
26
|
+
prec_max = prec_step.size - 1
|
27
|
+
tfmt = update_tfmt(prec_step[prec_nr])
|
28
|
+
events = []
|
29
|
+
interval = 1.0 / 10 ** prec_nr
|
30
|
+
|
31
|
+
def show_events(lineno, screen, events)
|
32
|
+
Curses.setpos(lineno += 1, 0)
|
33
|
+
Curses.clrtoeol
|
34
|
+
Curses.addstr('Events:')
|
35
|
+
maxy = screen.maxy - 1
|
36
|
+
maxx = screen.maxx
|
37
|
+
events.reverse_each do |e|
|
38
|
+
Curses.setpos(lineno += 1, 0)
|
39
|
+
Curses.clrtoeol
|
40
|
+
extra = e.size/maxx
|
41
|
+
break if (lineno + extra) >= maxy
|
42
|
+
|
43
|
+
# deal with long lines
|
44
|
+
if extra
|
45
|
+
rewind = lineno
|
46
|
+
extra.times do
|
47
|
+
Curses.setpos(lineno += 1, 0)
|
48
|
+
Curses.clrtoeol
|
49
|
+
end
|
50
|
+
Curses.setpos(rewind, 0)
|
51
|
+
Curses.addstr(e)
|
52
|
+
Curses.setpos(lineno, 0)
|
53
|
+
else
|
54
|
+
Curses.addstr(e)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# discard events we can't show
|
59
|
+
nr_events = events.size
|
60
|
+
if nr_events > maxy
|
61
|
+
events = events[(nr_events - maxy)..-1]
|
62
|
+
until lineno >= screen.maxy
|
63
|
+
Curses.setpos(lineno += 1, 0)
|
64
|
+
Curses.clrtoeol
|
65
|
+
end
|
66
|
+
else
|
67
|
+
Curses.setpos(maxy + 1, 0)
|
68
|
+
Curses.clrtoeol
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
begin
|
73
|
+
Curses.init_screen
|
74
|
+
Curses.nonl
|
75
|
+
Curses.cbreak
|
76
|
+
Curses.noecho
|
77
|
+
screen = Curses.stdscr
|
78
|
+
screen.scrollok(true)
|
79
|
+
screen.keypad(true)
|
80
|
+
loop do
|
81
|
+
lineno = -1
|
82
|
+
if current = cur['current']
|
83
|
+
Curses.setpos(lineno += 1, 0)
|
84
|
+
Curses.clrtoeol
|
85
|
+
Curses.addstr(current['infile'] || current['command'])
|
86
|
+
|
87
|
+
elapsed = Time.now.to_f - current['spawn_at']
|
88
|
+
if (nr = cur['current_initial']) && (current_format = current['format'])
|
89
|
+
rate = current_format['rate'].to_f
|
90
|
+
elapsed += nr / rate
|
91
|
+
total = " [#{Time.at(current['samples'] / rate).strftime(tfmt)}]"
|
92
|
+
else
|
93
|
+
total = ""
|
94
|
+
end
|
95
|
+
|
96
|
+
Curses.setpos(lineno += 1, 0)
|
97
|
+
Curses.clrtoeol
|
98
|
+
Curses.addstr("#{Time.at(elapsed).strftime(tfmt)}#{total}")
|
99
|
+
else
|
100
|
+
Curses.setpos(lineno += 1, 0)
|
101
|
+
Curses.clrtoeol
|
102
|
+
Curses.addstr(cur['paused'] ? 'paused' : 'idle')
|
103
|
+
Curses.setpos(lineno += 1, 0)
|
104
|
+
Curses.clrtoeol
|
105
|
+
end
|
106
|
+
|
107
|
+
show_events(lineno, screen, events)
|
108
|
+
|
109
|
+
Curses.refresh # draw and wait
|
110
|
+
r = IO.select(readable, nil, nil, current ? interval : nil) or next
|
111
|
+
r[0].each do |io|
|
112
|
+
case io
|
113
|
+
when w
|
114
|
+
event = w.res_wait
|
115
|
+
events << "#{Time.now.strftime(tfmt)} #{event}"
|
116
|
+
# something happened, refresh current
|
117
|
+
# we could be more intelligent here, maybe, but too much work.
|
118
|
+
cur = YAML.load(c.req('current'))
|
119
|
+
when $stdin
|
120
|
+
# keybindings taken from mplayer / vi
|
121
|
+
case key = Curses.getch
|
122
|
+
when "j" then c.req_ok("seek +5")
|
123
|
+
when "k" then c.req_ok("seek -5")
|
124
|
+
when Curses::KEY_DOWN then c.req_ok("seek -60")
|
125
|
+
when Curses::KEY_UP then c.req_ok("seek +60")
|
126
|
+
when Curses::KEY_LEFT then c.req_ok("seek -10")
|
127
|
+
when Curses::KEY_RIGHT then c.req_ok("seek +10")
|
128
|
+
when Curses::KEY_BACKSPACE then c.req_ok("seek 0")
|
129
|
+
# yes, some of us have long audio files
|
130
|
+
when Curses::KEY_PPAGE then c.req_ok("seek +600")
|
131
|
+
when Curses::KEY_NPAGE then c.req_ok("seek -600")
|
132
|
+
when " "
|
133
|
+
c.req("play_pause")
|
134
|
+
when "p" # lower precision of time display
|
135
|
+
if prec_nr >= 1
|
136
|
+
prec_nr -= 1
|
137
|
+
tfmt = update_tfmt(prec_step[prec_nr])
|
138
|
+
interval = 1.0 / 10 ** prec_nr
|
139
|
+
end
|
140
|
+
when "P" # increase precision of time display
|
141
|
+
if prec_nr < prec_max
|
142
|
+
prec_nr += 1
|
143
|
+
tfmt = update_tfmt(prec_step[prec_nr])
|
144
|
+
interval = 1.0 / 10 ** prec_nr
|
145
|
+
end
|
146
|
+
when 27 # TODO readline/edit mode?
|
147
|
+
else
|
148
|
+
Curses.setpos(screen.maxy - 1, 0)
|
149
|
+
Curses.clrtoeol
|
150
|
+
Curses.addstr("unknown key=#{key.inspect}")
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
rescue EOFError
|
156
|
+
Curses.close_screen
|
157
|
+
abort "dtas-player exited"
|
158
|
+
ensure
|
159
|
+
Curses.close_screen
|
160
|
+
end
|
data/bin/dtas-ctl
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
4
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
5
|
+
require 'dtas/unix_client'
|
6
|
+
|
7
|
+
# Unix paths are encoding agnostic
|
8
|
+
ARGV.map! { |arg| arg.b }
|
9
|
+
c = DTAS::UNIXClient.new
|
10
|
+
puts c.req(ARGV)
|
data/bin/dtas-cueedit
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
4
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
5
|
+
require 'tempfile'
|
6
|
+
require 'shellwords'
|
7
|
+
usage = "Usage: #$0 FILENAME"
|
8
|
+
editor = ENV["VISUAL"] || ENV["EDITOR"]
|
9
|
+
ARGV.size > 0 or abort usage
|
10
|
+
|
11
|
+
def err_msg(cmd, status)
|
12
|
+
err_cmd = cmd.map { |f| Shellwords.escape(f) }.join(' ')
|
13
|
+
"E: #{err_cmd} failed: #{status.inspect}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def x!(*cmd)
|
17
|
+
system(*cmd) or abort err_msg(cmd, $?)
|
18
|
+
end
|
19
|
+
|
20
|
+
def tmpfile(file, suffix)
|
21
|
+
tmp = Tempfile.new([File.basename(file), suffix])
|
22
|
+
tmp.sync = true
|
23
|
+
tmp.binmode
|
24
|
+
tmp
|
25
|
+
end
|
26
|
+
|
27
|
+
ARGV.each do |file|
|
28
|
+
# Unix paths are encoding agnostic
|
29
|
+
file = file.b
|
30
|
+
file =~ /\.flac\z/i or warn "Unsupported suffix, assuming FLAC"
|
31
|
+
tmp = tmpfile(file, '.cue')
|
32
|
+
begin
|
33
|
+
# export the temporary file for the user to edit
|
34
|
+
if system(*%W(metaflac --export-cuesheet-to=#{tmp.path} #{file}))
|
35
|
+
remove_existing = true
|
36
|
+
backup = tmpfile(file, '.backup.cue')
|
37
|
+
else
|
38
|
+
remove_existing = false
|
39
|
+
backup = nil
|
40
|
+
tmp.puts 'FILE "dtas-cueedit.tmp.flac" FLAC'
|
41
|
+
tmp.puts ' TRACK 01 AUDIO'
|
42
|
+
tmp.puts ' INDEX 01 00:00:00'
|
43
|
+
end
|
44
|
+
|
45
|
+
# keep a backup, in case the user screws up the edit
|
46
|
+
original = File.binread(tmp.path)
|
47
|
+
backup.write(original) if backup
|
48
|
+
|
49
|
+
# user edits the file
|
50
|
+
x!("#{editor} #{tmp.path}")
|
51
|
+
|
52
|
+
# avoid an expensive update if the user didn't change anything
|
53
|
+
current = File.binread(tmp.path)
|
54
|
+
if current == original
|
55
|
+
$stderr.puts "tags for #{Shellwords.escape(file)} unchanged" if $DEBUG
|
56
|
+
next
|
57
|
+
end
|
58
|
+
|
59
|
+
# we must remove existing tags before importing again
|
60
|
+
if remove_existing
|
61
|
+
x!(*%W(metaflac --remove --block-type=CUESHEET #{file}))
|
62
|
+
end
|
63
|
+
|
64
|
+
# try to import the new file but restore from the original backup if the
|
65
|
+
# user wrote an improperly formatted cue sheet
|
66
|
+
cmd = %W(metaflac --import-cuesheet-from=#{tmp.path} #{file})
|
67
|
+
if ! system(*cmd) && backup
|
68
|
+
warn err_msg(cmd, $?)
|
69
|
+
warn "E: restoring original from backup"
|
70
|
+
x!(*%W(metaflac --import-cuesheet-from=#{backup.path} #{file}))
|
71
|
+
warn "E: backup cuesheet restored, #{Shellwords.escape(file)} unchanged"
|
72
|
+
exit(false)
|
73
|
+
end
|
74
|
+
ensure
|
75
|
+
tmp.close!
|
76
|
+
backup.close! if backup
|
77
|
+
end
|
78
|
+
end
|
data/bin/dtas-enq
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
4
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
5
|
+
require 'dtas/unix_client'
|
6
|
+
c = DTAS::UNIXClient.new
|
7
|
+
|
8
|
+
ARGV.each do |path|
|
9
|
+
# Unix paths are encoding agnostic
|
10
|
+
path = File.expand_path(path.b)
|
11
|
+
res = c.req_ok(%W(enq #{path}))
|
12
|
+
puts "#{path} #{res}"
|
13
|
+
end
|
data/bin/dtas-msinkctl
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
4
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
5
|
+
require 'yaml'
|
6
|
+
require 'dtas/unix_client'
|
7
|
+
usage = "#$0 <active-set|active-add|active-sub|nonblock|active> SINK"
|
8
|
+
c = DTAS::UNIXClient.new
|
9
|
+
action = ARGV.shift
|
10
|
+
sink_args = ARGV
|
11
|
+
|
12
|
+
buf = c.req("sink ls")
|
13
|
+
abort(buf) if buf =~ /\AERR/
|
14
|
+
player_sinks = buf.split(/ /)
|
15
|
+
|
16
|
+
non_existent = sink_args - player_sinks
|
17
|
+
non_existent[0] and
|
18
|
+
abort "non-existent sink(s): #{non_existent.join(' ')}"
|
19
|
+
|
20
|
+
def activate_sinks(c, sink_names)
|
21
|
+
sink_names.each { |name| c.req_ok("sink ed #{name} active=true") }
|
22
|
+
end
|
23
|
+
|
24
|
+
def deactivate_sinks(c, sink_names)
|
25
|
+
sink_names.each { |name| c.req_ok("sink ed #{name} active=false") }
|
26
|
+
end
|
27
|
+
|
28
|
+
def filter(c, player_sinks, key)
|
29
|
+
rv = []
|
30
|
+
player_sinks.each do |name|
|
31
|
+
buf = c.req("sink cat #{name}")
|
32
|
+
sink = YAML.load(buf)
|
33
|
+
rv << sink["name"] if sink[key]
|
34
|
+
end
|
35
|
+
rv
|
36
|
+
end
|
37
|
+
|
38
|
+
case action
|
39
|
+
when "active-set"
|
40
|
+
activate_sinks(c, sink_args)
|
41
|
+
deactivate_sinks(c, player_sinks - sink_args)
|
42
|
+
when "active-add" # idempotent
|
43
|
+
activate_sinks(c, sink_args)
|
44
|
+
when "active-sub"
|
45
|
+
deactivate_sinks(c, sink_args)
|
46
|
+
when "active", "nonblock"
|
47
|
+
abort "`#$0 #{action}' takes no arguments" if sink_args[0]
|
48
|
+
puts filter(c, player_sinks, action).join(' ')
|
49
|
+
else
|
50
|
+
abort usage
|
51
|
+
end
|
data/bin/dtas-player
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
4
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
5
|
+
Thread.abort_on_exception = $stderr.sync = $stdout.sync = true
|
6
|
+
require 'yaml'
|
7
|
+
require 'dtas/player'
|
8
|
+
sock = (ENV["DTAS_PLAYER_SOCK"] ||
|
9
|
+
File.expand_path("~/.dtas/player.sock")).b
|
10
|
+
state = (ENV["DTAS_PLAYER_STATE"] ||
|
11
|
+
File.expand_path("~/.dtas/player_state.yml")).b
|
12
|
+
[ sock, state ].each do |file|
|
13
|
+
dir = File.dirname(file)
|
14
|
+
next if File.directory?(dir)
|
15
|
+
require 'fileutils'
|
16
|
+
FileUtils.mkpath(dir)
|
17
|
+
end
|
18
|
+
|
19
|
+
state = DTAS::StateFile.new(state)
|
20
|
+
if tmp = state.tryload
|
21
|
+
tmp["socket"] ||= sock
|
22
|
+
player = DTAS::Player.load(tmp)
|
23
|
+
player.state_file ||= state
|
24
|
+
else
|
25
|
+
player = DTAS::Player.new
|
26
|
+
player.state_file = state
|
27
|
+
player.socket = sock
|
28
|
+
end
|
29
|
+
|
30
|
+
at_exit { player.close }
|
31
|
+
player.bind
|
32
|
+
trap(:INT) { exit }
|
33
|
+
trap(:TERM) { exit }
|
34
|
+
player.run
|
data/bin/dtas-sinkedit
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
4
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
5
|
+
require 'dtas/unix_client'
|
6
|
+
require 'dtas/disclaimer'
|
7
|
+
require 'tempfile'
|
8
|
+
require 'yaml'
|
9
|
+
editor = ENV["VISUAL"] || ENV["EDITOR"]
|
10
|
+
c = DTAS::UNIXClient.new
|
11
|
+
usage = "#$0 SINKNAME"
|
12
|
+
ARGV.size == 1 or abort usage
|
13
|
+
name = ARGV[0]
|
14
|
+
|
15
|
+
tmp = Tempfile.new(%w(dtas-sinkedit .yml))
|
16
|
+
tmp.sync = true
|
17
|
+
tmp.binmode
|
18
|
+
|
19
|
+
buf = c.req(%W(sink cat #{name}))
|
20
|
+
abort(buf) if buf =~ /\AERR/
|
21
|
+
orig = YAML.load(buf)
|
22
|
+
|
23
|
+
tmp.write(buf << DTAS_DISCLAIMER)
|
24
|
+
cmd = "#{editor} #{tmp.path}"
|
25
|
+
system(cmd) or abort "#{cmd} failed: #$?"
|
26
|
+
tmp.rewind
|
27
|
+
sink = YAML.load(tmp.read)
|
28
|
+
|
29
|
+
cmd = %W(sink ed #{name})
|
30
|
+
if env = sink["env"]
|
31
|
+
env.each do |k,v|
|
32
|
+
cmd << (v.nil? ? "env##{k}" : "env.#{k}=#{v}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# remove deleted env
|
37
|
+
if orig_env = orig["env"]
|
38
|
+
env ||= {}
|
39
|
+
deleted_keys = orig_env.keys - env.keys
|
40
|
+
deleted_keys.each { |k| cmd << "env##{k}" }
|
41
|
+
end
|
42
|
+
|
43
|
+
%w(nonblock active).each do |field|
|
44
|
+
if sink.key?(field)
|
45
|
+
cmd << "#{field}=#{sink[field] ? 'true' : 'false'}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
%w(prio pipe_size).each do |field|
|
50
|
+
value = sink[field] and cmd << "#{field}=#{value}"
|
51
|
+
end
|
52
|
+
|
53
|
+
%w(command).each do |field|
|
54
|
+
value = sink[field]
|
55
|
+
cmd << "#{field}=#{value}"
|
56
|
+
end
|
57
|
+
|
58
|
+
c.req_ok(cmd)
|
data/bin/dtas-sourceedit
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
|
4
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
5
|
+
require 'tempfile'
|
6
|
+
require 'yaml'
|
7
|
+
require 'dtas/unix_client'
|
8
|
+
require 'dtas/disclaimer'
|
9
|
+
editor = ENV["VISUAL"] || ENV["EDITOR"]
|
10
|
+
c = DTAS::UNIXClient.new
|
11
|
+
usage = $0
|
12
|
+
ARGV.size == 0 or abort usage
|
13
|
+
name = ARGV[0]
|
14
|
+
|
15
|
+
tmp = Tempfile.new(%w(dtas-sourceedit .yml))
|
16
|
+
tmp.sync = true
|
17
|
+
tmp.binmode
|
18
|
+
|
19
|
+
buf = c.req(%W(source cat))
|
20
|
+
abort(buf) if buf =~ /\AERR/
|
21
|
+
orig = YAML.load(buf)
|
22
|
+
|
23
|
+
tmp.write(buf << DTAS_DISCLAIMER)
|
24
|
+
cmd = "#{editor} #{tmp.path}"
|
25
|
+
system(cmd) or abort "#{cmd} failed: #$?"
|
26
|
+
tmp.rewind
|
27
|
+
source = YAML.load(tmp.read)
|
28
|
+
|
29
|
+
cmd = %W(source ed)
|
30
|
+
if env = source["env"]
|
31
|
+
env.each do |k,v|
|
32
|
+
cmd << (v.nil? ? "env##{k}" : "env.#{k}=#{v}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# remove deleted env
|
37
|
+
if orig_env = orig["env"]
|
38
|
+
env ||= {}
|
39
|
+
deleted_keys = orig_env.keys - env.keys
|
40
|
+
deleted_keys.each { |k| cmd << "env##{k}" }
|
41
|
+
end
|
42
|
+
|
43
|
+
%w(command).each do |field|
|
44
|
+
value = source[field]
|
45
|
+
cmd << "#{field}=#{value}"
|
46
|
+
end
|
47
|
+
|
48
|
+
c.req_ok(cmd)
|