debug 1.0.0.beta4 → 1.0.0.beta8
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 +4 -4
- data/.github/workflows/ruby.yml +34 -0
- data/.gitignore +1 -0
- data/CONTRIBUTING.md +239 -0
- data/Gemfile +2 -1
- data/README.md +424 -215
- data/Rakefile +2 -1
- data/TODO.md +0 -6
- data/bin/gentest +22 -0
- data/debug.gemspec +2 -0
- data/exe/rdbg +14 -11
- data/ext/debug/debug.c +9 -8
- data/lib/debug.rb +3 -0
- data/lib/debug/breakpoint.rb +101 -43
- data/lib/debug/client.rb +55 -13
- data/lib/debug/color.rb +76 -0
- data/lib/debug/config.rb +130 -39
- data/lib/debug/console.rb +24 -3
- data/lib/debug/frame_info.rb +63 -31
- data/lib/debug/open.rb +4 -1
- data/lib/debug/open_nonstop.rb +15 -0
- data/lib/debug/server.rb +90 -32
- data/lib/debug/server_dap.rb +607 -0
- data/lib/debug/session.rb +461 -174
- data/lib/debug/source_repository.rb +55 -33
- data/lib/debug/start.rb +5 -0
- data/lib/debug/thread_client.rb +176 -59
- data/lib/debug/version.rb +3 -1
- data/misc/README.md.erb +351 -204
- metadata +23 -4
- data/lib/debug/run.rb +0 -2
data/lib/debug/client.rb
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'socket'
|
|
4
|
+
require 'io/console/size'
|
|
5
|
+
|
|
2
6
|
require_relative 'config'
|
|
7
|
+
require_relative 'version'
|
|
8
|
+
|
|
9
|
+
# $VERBOSE = true
|
|
3
10
|
|
|
4
11
|
module DEBUGGER__
|
|
5
12
|
class CommandLineOptionError < Exception; end
|
|
@@ -8,16 +15,18 @@ module DEBUGGER__
|
|
|
8
15
|
begin
|
|
9
16
|
require 'readline'
|
|
10
17
|
def readline
|
|
11
|
-
Readline.readline("\n(
|
|
18
|
+
Readline.readline("\n(rdbg:remote) ", true)
|
|
12
19
|
end
|
|
13
20
|
rescue LoadError
|
|
14
21
|
def readline
|
|
15
|
-
print "\n(
|
|
22
|
+
print "\n(rdbg:remote) "
|
|
16
23
|
gets
|
|
17
24
|
end
|
|
18
25
|
end
|
|
19
26
|
|
|
20
27
|
def initialize argv
|
|
28
|
+
return util(argv) if String === argv
|
|
29
|
+
|
|
21
30
|
case argv.size
|
|
22
31
|
when 0
|
|
23
32
|
connect_unix
|
|
@@ -36,6 +45,24 @@ module DEBUGGER__
|
|
|
36
45
|
else
|
|
37
46
|
raise CommandLineOptionError
|
|
38
47
|
end
|
|
48
|
+
|
|
49
|
+
@width = IO.console_size[1]
|
|
50
|
+
@width = 80 if @width == 0
|
|
51
|
+
@width_changed = false
|
|
52
|
+
|
|
53
|
+
send "version: #{VERSION} width: #{@width} cookie: #{CONFIG[:cookie]}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def util name
|
|
57
|
+
case name
|
|
58
|
+
when 'gen-sockpath'
|
|
59
|
+
puts DEBUGGER__.create_unix_domain_socket_name
|
|
60
|
+
when 'list-socks'
|
|
61
|
+
cleanup_unix_domain_sockets
|
|
62
|
+
puts list_connections
|
|
63
|
+
else
|
|
64
|
+
raise "Unknown utility: #{name}"
|
|
65
|
+
end
|
|
39
66
|
end
|
|
40
67
|
|
|
41
68
|
def cleanup_unix_domain_sockets
|
|
@@ -50,16 +77,20 @@ module DEBUGGER__
|
|
|
50
77
|
end
|
|
51
78
|
end
|
|
52
79
|
|
|
80
|
+
def list_connections
|
|
81
|
+
Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*')
|
|
82
|
+
end
|
|
83
|
+
|
|
53
84
|
def connect_unix name = nil
|
|
54
85
|
if name
|
|
55
86
|
if File.exist? name
|
|
56
87
|
@s = Socket.unix(name)
|
|
57
88
|
else
|
|
58
|
-
@s = Socket.unix(File.join(DEBUGGER__.
|
|
89
|
+
@s = Socket.unix(File.join(DEBUGGER__.unix_domain_socket_dir, name))
|
|
59
90
|
end
|
|
60
91
|
else
|
|
61
92
|
cleanup_unix_domain_sockets
|
|
62
|
-
files =
|
|
93
|
+
files = list_connections
|
|
63
94
|
case files.size
|
|
64
95
|
when 0
|
|
65
96
|
$stderr.puts "No debug session is available."
|
|
@@ -80,13 +111,22 @@ module DEBUGGER__
|
|
|
80
111
|
@s = Socket.tcp(host, port)
|
|
81
112
|
end
|
|
82
113
|
|
|
114
|
+
def send msg
|
|
115
|
+
p send: msg if $VERBOSE
|
|
116
|
+
@s.puts msg
|
|
117
|
+
end
|
|
118
|
+
|
|
83
119
|
def connect
|
|
84
120
|
trap(:SIGINT){
|
|
85
|
-
|
|
121
|
+
send "pause"
|
|
122
|
+
}
|
|
123
|
+
trap(:SIGWINCH){
|
|
124
|
+
@width = IO.console_size[1]
|
|
125
|
+
@width_changed = true
|
|
86
126
|
}
|
|
87
127
|
|
|
88
128
|
while line = @s.gets
|
|
89
|
-
|
|
129
|
+
p recv: line if $VERBOSE
|
|
90
130
|
case line
|
|
91
131
|
when /^out (.*)/
|
|
92
132
|
puts "#{$1}"
|
|
@@ -102,10 +142,16 @@ module DEBUGGER__
|
|
|
102
142
|
end
|
|
103
143
|
|
|
104
144
|
line = (line || 'quit').strip
|
|
105
|
-
|
|
145
|
+
|
|
146
|
+
if @width_changed
|
|
147
|
+
@width_changed = false
|
|
148
|
+
send "width #{@width}"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
send "command #{line}"
|
|
106
152
|
when /^ask (.*)/
|
|
107
153
|
print $1
|
|
108
|
-
|
|
154
|
+
send "answer #{gets || ''}"
|
|
109
155
|
when /^quit/
|
|
110
156
|
raise 'quit'
|
|
111
157
|
else
|
|
@@ -119,10 +165,6 @@ module DEBUGGER__
|
|
|
119
165
|
end
|
|
120
166
|
end
|
|
121
167
|
|
|
122
|
-
def connect argv = ARGV
|
|
123
|
-
DEBUGGER__::Client.new(argv).connect
|
|
124
|
-
end
|
|
125
|
-
|
|
126
168
|
if __FILE__ == $0
|
|
127
|
-
connect
|
|
169
|
+
DEBUGGER__::Client.new(argv).connect
|
|
128
170
|
end
|
data/lib/debug/color.rb
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'irb/color'
|
|
5
|
+
require "irb/color_printer"
|
|
6
|
+
rescue LoadError
|
|
7
|
+
warn "DEBUGGER: can not load newer irb for coloring. Write 'gem \"debug\" in your Gemfile."
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module DEBUGGER__
|
|
11
|
+
module Color
|
|
12
|
+
if defined? IRB::Color.colorize
|
|
13
|
+
def colorize str, color
|
|
14
|
+
if !CONFIG[:no_color]
|
|
15
|
+
IRB::Color.colorize str, color
|
|
16
|
+
else
|
|
17
|
+
str
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
def colorize str, color
|
|
22
|
+
str
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if defined? IRB::ColorPrinter.pp
|
|
27
|
+
def color_pp obj, width = SESSION.width
|
|
28
|
+
if !CONFIG[:no_color]
|
|
29
|
+
IRB::ColorPrinter.pp(obj, "".dup, width)
|
|
30
|
+
else
|
|
31
|
+
obj.pretty_inspect
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
def color_pp obj
|
|
36
|
+
obj.pretty_inspect
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def colored_inspect obj, no_color: false
|
|
41
|
+
if !no_color
|
|
42
|
+
color_pp obj
|
|
43
|
+
else
|
|
44
|
+
obj.pretty_inspect
|
|
45
|
+
end
|
|
46
|
+
rescue => ex
|
|
47
|
+
err_msg = "#{ex.inspect} rescued during inspection"
|
|
48
|
+
string_result = obj.to_s rescue nil
|
|
49
|
+
|
|
50
|
+
# don't colorize the string here because it's not from user's application
|
|
51
|
+
if string_result
|
|
52
|
+
%Q{"#{string_result}" from #to_s because #{err_msg}}
|
|
53
|
+
else
|
|
54
|
+
err_msg
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if defined? IRB::Color.colorize_code
|
|
59
|
+
def colorize_code code
|
|
60
|
+
IRB::Color.colorize_code(code)
|
|
61
|
+
end
|
|
62
|
+
else
|
|
63
|
+
def colorize_code code
|
|
64
|
+
code
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def colorize_cyan(str)
|
|
69
|
+
colorize(str, [:CYAN, :BOLD])
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def colorize_blue(str)
|
|
73
|
+
colorize(str, [:BLUE, :BOLD])
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
data/lib/debug/config.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
|
|
2
3
|
module DEBUGGER__
|
|
3
4
|
def self.unix_domain_socket_dir
|
|
@@ -29,83 +30,139 @@ module DEBUGGER__
|
|
|
29
30
|
create_unix_domain_socket_name_prefix(base_dir) + "-#{Process.pid}"
|
|
30
31
|
end
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
# boot setting
|
|
34
|
-
nonstop: 'RUBY_DEBUG_NONSTOP', # Nonstop mode ('1' is nonstop)
|
|
35
|
-
init_script: 'RUBY_DEBUG_INIT_SCRIPT', # debug command script path loaded at first stop
|
|
36
|
-
commands: 'RUBY_DEBUG_COMMANDS', # debug commands invoked at first stop. commands should be separated by ';;'
|
|
37
|
-
|
|
33
|
+
CONFIG_SET = {
|
|
38
34
|
# UI setting
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
35
|
+
log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger (default: WARN)", :loglevel],
|
|
36
|
+
show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint (default: 10 lines)", :int],
|
|
37
|
+
show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint (default: 2 frames)", :int],
|
|
38
|
+
show_info_lines:['RUBY_DEBUG_SHOW_INFO_LINES',"UI: Show n lines on info command (default: 10 lines, 0 for unlimited)", :int],
|
|
39
|
+
use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shoten PATH (like $(Gem)/foo.rb)", :bool],
|
|
40
|
+
skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "UI: Skip on no source code lines (default: false)", :bool],
|
|
41
|
+
skip_path: ['RUBY_DEBUG_SKIP_PATH', "UI: Skip showing frames for given paths (default: [])", :path],
|
|
42
|
+
no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize (default: false)", :bool],
|
|
43
|
+
no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT (default: false)", :bool],
|
|
44
|
+
|
|
45
|
+
# boot setting
|
|
46
|
+
nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool],
|
|
47
|
+
init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"],
|
|
48
|
+
commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. commands should be separated by ';;'"],
|
|
49
|
+
no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool],
|
|
50
|
+
|
|
51
|
+
# remote setting
|
|
52
|
+
port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"],
|
|
53
|
+
host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host (localhost if not given)"],
|
|
54
|
+
sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"],
|
|
55
|
+
sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"],
|
|
56
|
+
cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"],
|
|
50
57
|
}.freeze
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
59
|
+
CONFIG_MAP = CONFIG_SET.map{|k, (ev, desc)| [k, ev]}.to_h.freeze
|
|
60
|
+
|
|
61
|
+
def self.config_to_env_hash config
|
|
62
|
+
CONFIG_MAP.each_with_object({}){|(key, evname), env|
|
|
63
|
+
env[evname] = config[key].to_s if config[key]
|
|
55
64
|
}
|
|
56
65
|
end
|
|
57
66
|
|
|
67
|
+
def self.parse_config_value name, valstr
|
|
68
|
+
return valstr unless valstr.kind_of? String
|
|
69
|
+
|
|
70
|
+
case CONFIG_SET[name][2]
|
|
71
|
+
when :bool
|
|
72
|
+
case valstr
|
|
73
|
+
when '1', 'true', 'TRUE', 'T'
|
|
74
|
+
true
|
|
75
|
+
else
|
|
76
|
+
false
|
|
77
|
+
end
|
|
78
|
+
when :int
|
|
79
|
+
valstr.to_i
|
|
80
|
+
when :loglevel
|
|
81
|
+
if DEBUGGER__::LOG_LEVELS[s = valstr.to_sym]
|
|
82
|
+
s
|
|
83
|
+
else
|
|
84
|
+
raise "Unknown loglevel: #{valstr}"
|
|
85
|
+
end
|
|
86
|
+
when :path # array of String
|
|
87
|
+
valstr.split(/:/).map{|e|
|
|
88
|
+
if /\A\/(.+)\/\z/ =~ e
|
|
89
|
+
Regexp.compile $1
|
|
90
|
+
else
|
|
91
|
+
e
|
|
92
|
+
end
|
|
93
|
+
}
|
|
94
|
+
else
|
|
95
|
+
valstr
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
58
99
|
def self.parse_argv argv
|
|
59
100
|
config = {
|
|
60
101
|
mode: :start,
|
|
61
|
-
use_colorize: true,
|
|
62
102
|
}
|
|
63
103
|
CONFIG_MAP.each{|key, evname|
|
|
64
104
|
if val = ENV[evname]
|
|
65
|
-
|
|
66
|
-
case val
|
|
67
|
-
when '1', 'true', 'TRUE', 'T'
|
|
68
|
-
config[key] = true
|
|
69
|
-
else
|
|
70
|
-
config[key] = false
|
|
71
|
-
end
|
|
72
|
-
else
|
|
73
|
-
config[key] = val
|
|
74
|
-
end
|
|
105
|
+
config[key] = parse_config_value(key, val)
|
|
75
106
|
end
|
|
76
107
|
}
|
|
77
108
|
return config if !argv || argv.empty?
|
|
78
109
|
|
|
79
110
|
require 'optparse'
|
|
111
|
+
require_relative 'version'
|
|
80
112
|
|
|
81
113
|
opt = OptionParser.new do |o|
|
|
82
114
|
o.banner = "#{$0} [options] -- [debuggee options]"
|
|
83
115
|
o.separator ''
|
|
116
|
+
o.version = ::DEBUGGER__::VERSION
|
|
84
117
|
|
|
85
118
|
o.separator 'Debug console mode:'
|
|
86
119
|
o.on('-n', '--nonstop', 'Do not stop at the beginning of the script.') do
|
|
87
120
|
config[:nonstop] = '1'
|
|
88
121
|
end
|
|
89
122
|
|
|
90
|
-
o.on('-e
|
|
123
|
+
o.on('-e DEBUG_COMMAND', 'Execute debug command at the beginning of the script.') do |cmd|
|
|
91
124
|
config[:commands] ||= ''
|
|
92
|
-
config[:commands]
|
|
125
|
+
config[:commands] += cmd + ';;'
|
|
93
126
|
end
|
|
94
127
|
|
|
95
|
-
o.on('-
|
|
128
|
+
o.on('-x FILE', '--init-script=FILE', 'Execute debug command in the FILE.') do |file|
|
|
129
|
+
config[:init_script] = file
|
|
130
|
+
end
|
|
131
|
+
o.on('--no-rc', 'Ignore ~/.rdbgrc') do
|
|
132
|
+
config[:no_rc] = true
|
|
133
|
+
end
|
|
134
|
+
o.on('--no-color', 'Disable colorize') do
|
|
135
|
+
config[:no_color] = true
|
|
136
|
+
end
|
|
137
|
+
o.on('--no-sigint-hook', 'Disable to trap SIGINT') do
|
|
138
|
+
config[:no_sigint_hook] = true
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
o.on('-c', '--command', 'Enable command mode.',
|
|
142
|
+
'The first argument should be a command name in $PATH.',
|
|
143
|
+
'Example: \'rdbg -c bundle exec rake test\'') do
|
|
144
|
+
config[:command] = true
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
o.separator ''
|
|
148
|
+
|
|
149
|
+
o.on('-O', '--open', 'Start remote debugging with opening the network port.',
|
|
96
150
|
'If TCP/IP options are not given,',
|
|
97
151
|
'a UNIX domain socket will be used.') do
|
|
98
152
|
config[:remote] = true
|
|
99
153
|
end
|
|
100
|
-
o.on('--sock-path=
|
|
154
|
+
o.on('--sock-path=SOCK_PATH', 'UNIX Doman socket path') do |path|
|
|
101
155
|
config[:sock_path] = path
|
|
102
156
|
end
|
|
103
|
-
o.on('--port=
|
|
157
|
+
o.on('--port=PORT', 'Listening TCP/IP port') do |port|
|
|
104
158
|
config[:port] = port
|
|
105
159
|
end
|
|
106
|
-
o.on('--host=
|
|
160
|
+
o.on('--host=HOST', 'Listening TCP/IP host') do |host|
|
|
107
161
|
config[:host] = host
|
|
108
162
|
end
|
|
163
|
+
o.on('--cookie=COOKIE', 'Set a cookie for connection') do |c|
|
|
164
|
+
config[:cookie] = c
|
|
165
|
+
end
|
|
109
166
|
|
|
110
167
|
rdbg = 'rdbg'
|
|
111
168
|
|
|
@@ -114,6 +171,9 @@ module DEBUGGER__
|
|
|
114
171
|
o.separator ''
|
|
115
172
|
o.separator " '#{rdbg} target.rb foo bar' starts like 'ruby target.rb foo bar'."
|
|
116
173
|
o.separator " '#{rdbg} -- -r foo -e bar' starts like 'ruby -r foo -e bar'."
|
|
174
|
+
o.separator " '#{rdbg} -c rake test' starts like 'rake test'."
|
|
175
|
+
o.separator " '#{rdbg} -c -- rake test -t' starts like 'rake test -t'."
|
|
176
|
+
o.separator " '#{rdbg} -c bundle exec rake test' starts like 'bundle exec rake test'."
|
|
117
177
|
o.separator " '#{rdbg} -O target.rb foo bar' starts and accepts attaching with UNIX domain socket."
|
|
118
178
|
o.separator " '#{rdbg} -O --port 1234 target.rb foo bar' starts accepts attaching with TCP/IP localhost:1234."
|
|
119
179
|
o.separator " '#{rdbg} -O --port 1234 -- -r foo -e bar' starts accepts attaching with TCP/IP localhost:1234."
|
|
@@ -133,6 +193,25 @@ module DEBUGGER__
|
|
|
133
193
|
o.separator " '#{rdbg} -A path' tries to connect via UNIX domain socket with given path name."
|
|
134
194
|
o.separator " '#{rdbg} -A port' tries to connect to localhost:port via TCP/IP."
|
|
135
195
|
o.separator " '#{rdbg} -A host port' tries to connect to host:port via TCP/IP."
|
|
196
|
+
|
|
197
|
+
o.separator ''
|
|
198
|
+
o.separator 'Other options:'
|
|
199
|
+
|
|
200
|
+
o.on("-h", "--help", "Print help") do
|
|
201
|
+
puts o
|
|
202
|
+
exit
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
o.on('--util=NAME', 'Utility mode (used by tools)') do |name|
|
|
206
|
+
require_relative 'client'
|
|
207
|
+
Client.new(name)
|
|
208
|
+
exit
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
o.separator ''
|
|
212
|
+
o.separator 'NOTE'
|
|
213
|
+
o.separator ' All messages communicated between a debugger and a debuggee are *NOT* encrypted.'
|
|
214
|
+
o.separator ' Please use the remote debugging feature carefully.'
|
|
136
215
|
end
|
|
137
216
|
|
|
138
217
|
opt.parse!(argv)
|
|
@@ -145,10 +224,22 @@ module DEBUGGER__
|
|
|
145
224
|
def self.set_config kw
|
|
146
225
|
kw.each{|k, v|
|
|
147
226
|
if CONFIG_MAP[k]
|
|
148
|
-
CONFIG[k] = v # TODO: ractor support
|
|
227
|
+
CONFIG[k] = parse_config_value(k, v) # TODO: ractor support
|
|
149
228
|
else
|
|
150
|
-
raise "
|
|
229
|
+
raise "Unknown configuration: #{k}"
|
|
151
230
|
end
|
|
152
231
|
}
|
|
153
232
|
end
|
|
233
|
+
|
|
234
|
+
def self.append_config key, val
|
|
235
|
+
if CONFIG_SET[key]
|
|
236
|
+
if CONFIG_SET[key][2] == :path
|
|
237
|
+
CONFIG[key] = [*CONFIG[key], *parse_config_value(key, val)];
|
|
238
|
+
else
|
|
239
|
+
raise "not an Array type: #{key}"
|
|
240
|
+
end
|
|
241
|
+
else
|
|
242
|
+
raise "Unknown configuration: #{key}"
|
|
243
|
+
end
|
|
244
|
+
end
|
|
154
245
|
end
|