readapt 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +16 -16
- data/.rspec +2 -2
- data/.travis.yml +19 -18
- data/CHANGELOG.md +87 -83
- data/Gemfile +4 -4
- data/LICENSE.txt +21 -21
- data/README.md +37 -37
- data/Rakefile +14 -14
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/exe/readapt +5 -5
- data/ext/readapt/breakpoints.c +83 -83
- data/ext/readapt/breakpoints.h +11 -11
- data/ext/readapt/extconf.rb +0 -0
- data/ext/readapt/frame.c +137 -137
- data/ext/readapt/frame.h +17 -17
- data/ext/readapt/inspector.c +51 -51
- data/ext/readapt/inspector.h +8 -8
- data/ext/readapt/lookup_table.c +211 -211
- data/ext/readapt/lookup_table.h +30 -30
- data/ext/readapt/monitor.c +0 -0
- data/ext/readapt/monitor.h +0 -0
- data/ext/readapt/normalize.c +59 -59
- data/ext/readapt/normalize.h +7 -7
- data/ext/readapt/readapt.c +18 -18
- data/ext/readapt/stack.c +86 -86
- data/ext/readapt/stack.h +20 -20
- data/ext/readapt/threads.c +0 -0
- data/ext/readapt/threads.h +0 -0
- data/lib/readapt.rb +21 -21
- data/lib/readapt/adapter.rb +98 -98
- data/lib/readapt/breakpoint.rb +21 -21
- data/lib/readapt/data_reader.rb +62 -62
- data/lib/readapt/debugger.rb +228 -220
- data/lib/readapt/error.rb +63 -63
- data/lib/readapt/finder.rb +34 -34
- data/lib/readapt/frame.rb +40 -40
- data/lib/readapt/input.rb +7 -7
- data/lib/readapt/message.rb +62 -62
- data/lib/readapt/message/attach.rb +11 -11
- data/lib/readapt/message/base.rb +32 -32
- data/lib/readapt/message/configuration_done.rb +11 -11
- data/lib/readapt/message/continue.rb +15 -15
- data/lib/readapt/message/disconnect.rb +13 -13
- data/lib/readapt/message/evaluate.rb +18 -18
- data/lib/readapt/message/initialize.rb +21 -13
- data/lib/readapt/message/launch.rb +11 -11
- data/lib/readapt/message/next.rb +12 -12
- data/lib/readapt/message/pause.rb +11 -11
- data/lib/readapt/message/scopes.rb +26 -26
- data/lib/readapt/message/set_breakpoints.rb +25 -25
- data/lib/readapt/message/set_exception_breakpoints.rb +11 -8
- data/lib/readapt/message/stack_trace.rb +38 -38
- data/lib/readapt/message/step_in.rb +11 -11
- data/lib/readapt/message/step_out.rb +11 -11
- data/lib/readapt/message/threads.rb +18 -18
- data/lib/readapt/message/variables.rb +53 -53
- data/lib/readapt/monitor.rb +0 -0
- data/lib/readapt/output.rb +25 -25
- data/lib/readapt/references.rb +27 -27
- data/lib/readapt/server.rb +22 -22
- data/lib/readapt/shell.rb +104 -104
- data/lib/readapt/snapshot.rb +0 -0
- data/lib/readapt/thread.rb +25 -25
- data/lib/readapt/variable.rb +0 -0
- data/lib/readapt/version.rb +3 -3
- data/readapt.gemspec +39 -39
- metadata +7 -7
@@ -1,11 +1,11 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Readapt
|
4
|
-
module Message
|
5
|
-
class StepOut < Base
|
6
|
-
def run
|
7
|
-
debugger.thread(arguments['threadId']).control = :step_out
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Readapt
|
4
|
+
module Message
|
5
|
+
class StepOut < Base
|
6
|
+
def run
|
7
|
+
debugger.thread(arguments['threadId']).control = :step_out
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -1,18 +1,18 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Readapt
|
4
|
-
module Message
|
5
|
-
class Threads < Base
|
6
|
-
def run
|
7
|
-
set_body({
|
8
|
-
threads: debugger.threads.map do |thr|
|
9
|
-
{
|
10
|
-
id: thr.id,
|
11
|
-
name: thr.name
|
12
|
-
}
|
13
|
-
end
|
14
|
-
})
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Readapt
|
4
|
+
module Message
|
5
|
+
class Threads < Base
|
6
|
+
def run
|
7
|
+
set_body({
|
8
|
+
threads: debugger.threads.map do |thr|
|
9
|
+
{
|
10
|
+
id: thr.id,
|
11
|
+
name: thr.name
|
12
|
+
}
|
13
|
+
end
|
14
|
+
})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,53 +1,53 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Readapt
|
4
|
-
module Message
|
5
|
-
class Variables < Base
|
6
|
-
def run
|
7
|
-
ref = arguments['variablesReference']
|
8
|
-
frame = debugger.frame(ref)
|
9
|
-
# @todo 1 is a magic number representing the toplevel binding (see
|
10
|
-
# Message::Scopes)
|
11
|
-
vars = if ref == 1
|
12
|
-
global_variables.map do |gv|
|
13
|
-
Variable.new(gv, eval(gv.to_s))
|
14
|
-
end
|
15
|
-
else
|
16
|
-
if frame != Frame::NULL_FRAME && !frame.nil?
|
17
|
-
frame.locals
|
18
|
-
else
|
19
|
-
obj = References.get(ref)
|
20
|
-
result = []
|
21
|
-
if obj.is_a?(Array)
|
22
|
-
obj.each_with_index do |itm, idx|
|
23
|
-
result.push Variable.new("[#{idx}]", itm)
|
24
|
-
end
|
25
|
-
elsif obj.is_a?(Hash)
|
26
|
-
obj.each_pair do |idx, itm|
|
27
|
-
result.push Variable.new("[#{idx}]", itm)
|
28
|
-
end
|
29
|
-
else
|
30
|
-
obj.instance_variables.sort.each do |iv|
|
31
|
-
result.push Variable.new(iv, obj.instance_variable_get(iv))
|
32
|
-
end
|
33
|
-
obj.class.class_variables.sort.each do |cv|
|
34
|
-
result.push Variable.new(cv, obj.class.class_variable_get(cv))
|
35
|
-
end
|
36
|
-
end
|
37
|
-
result
|
38
|
-
end
|
39
|
-
end
|
40
|
-
set_body({
|
41
|
-
variables: vars.map do |var|
|
42
|
-
{
|
43
|
-
name: var.name,
|
44
|
-
value: var.value,
|
45
|
-
type: var.type,
|
46
|
-
variablesReference: var.reference
|
47
|
-
}
|
48
|
-
end
|
49
|
-
})
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Readapt
|
4
|
+
module Message
|
5
|
+
class Variables < Base
|
6
|
+
def run
|
7
|
+
ref = arguments['variablesReference']
|
8
|
+
frame = debugger.frame(ref)
|
9
|
+
# @todo 1 is a magic number representing the toplevel binding (see
|
10
|
+
# Message::Scopes)
|
11
|
+
vars = if ref == 1
|
12
|
+
global_variables.map do |gv|
|
13
|
+
Variable.new(gv, eval(gv.to_s))
|
14
|
+
end
|
15
|
+
else
|
16
|
+
if frame != Frame::NULL_FRAME && !frame.nil?
|
17
|
+
frame.locals
|
18
|
+
else
|
19
|
+
obj = References.get(ref)
|
20
|
+
result = []
|
21
|
+
if obj.is_a?(Array)
|
22
|
+
obj.each_with_index do |itm, idx|
|
23
|
+
result.push Variable.new("[#{idx}]", itm)
|
24
|
+
end
|
25
|
+
elsif obj.is_a?(Hash)
|
26
|
+
obj.each_pair do |idx, itm|
|
27
|
+
result.push Variable.new("[#{idx}]", itm)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
obj.instance_variables.sort.each do |iv|
|
31
|
+
result.push Variable.new(iv, obj.instance_variable_get(iv))
|
32
|
+
end
|
33
|
+
obj.class.class_variables.sort.each do |cv|
|
34
|
+
result.push Variable.new(cv, obj.class.class_variable_get(cv))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
result
|
38
|
+
end
|
39
|
+
end
|
40
|
+
set_body({
|
41
|
+
variables: vars.map do |var|
|
42
|
+
{
|
43
|
+
name: var.name,
|
44
|
+
value: var.value,
|
45
|
+
type: var.type,
|
46
|
+
variablesReference: var.reference
|
47
|
+
}
|
48
|
+
end
|
49
|
+
})
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/readapt/monitor.rb
CHANGED
File without changes
|
data/lib/readapt/output.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
|
-
module Readapt
|
2
|
-
module Output
|
3
|
-
class << self
|
4
|
-
attr_accessor :adapter
|
5
|
-
end
|
6
|
-
|
7
|
-
def receiving data
|
8
|
-
send_event('output', {
|
9
|
-
output: data.force_encoding('utf-8'),
|
10
|
-
category: 'stdout'
|
11
|
-
})
|
12
|
-
end
|
13
|
-
|
14
|
-
def send_event event, data
|
15
|
-
obj = {
|
16
|
-
type: 'event',
|
17
|
-
event: event
|
18
|
-
}
|
19
|
-
obj[:body] = data unless data.nil?
|
20
|
-
json = obj.to_json
|
21
|
-
envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
|
22
|
-
Output.adapter.write envelope
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
1
|
+
module Readapt
|
2
|
+
module Output
|
3
|
+
class << self
|
4
|
+
attr_accessor :adapter
|
5
|
+
end
|
6
|
+
|
7
|
+
def receiving data
|
8
|
+
send_event('output', {
|
9
|
+
output: data.force_encoding('utf-8'),
|
10
|
+
category: 'stdout'
|
11
|
+
})
|
12
|
+
end
|
13
|
+
|
14
|
+
def send_event event, data
|
15
|
+
obj = {
|
16
|
+
type: 'event',
|
17
|
+
event: event
|
18
|
+
}
|
19
|
+
obj[:body] = data unless data.nil?
|
20
|
+
json = obj.to_json
|
21
|
+
envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
|
22
|
+
Output.adapter.write envelope
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/readapt/references.rb
CHANGED
@@ -1,27 +1,27 @@
|
|
1
|
-
module Readapt
|
2
|
-
module References
|
3
|
-
module_function
|
4
|
-
|
5
|
-
@variable_reference_map = {}
|
6
|
-
@reference_variable_map = {}
|
7
|
-
@reference_id = 1000
|
8
|
-
|
9
|
-
def clear
|
10
|
-
@variable_reference_map.clear
|
11
|
-
@reference_variable_map.clear
|
12
|
-
@reference_id = 1000
|
13
|
-
end
|
14
|
-
|
15
|
-
def identify object
|
16
|
-
return @variable_reference_map[object] if @variable_reference_map.has_key?(object)
|
17
|
-
@reference_id += 1
|
18
|
-
@variable_reference_map[object] = @reference_id
|
19
|
-
@reference_variable_map[@reference_id] = object
|
20
|
-
@reference_id
|
21
|
-
end
|
22
|
-
|
23
|
-
def get id
|
24
|
-
@reference_variable_map[id]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
1
|
+
module Readapt
|
2
|
+
module References
|
3
|
+
module_function
|
4
|
+
|
5
|
+
@variable_reference_map = {}
|
6
|
+
@reference_variable_map = {}
|
7
|
+
@reference_id = 1000
|
8
|
+
|
9
|
+
def clear
|
10
|
+
@variable_reference_map.clear
|
11
|
+
@reference_variable_map.clear
|
12
|
+
@reference_id = 1000
|
13
|
+
end
|
14
|
+
|
15
|
+
def identify object
|
16
|
+
return @variable_reference_map[object] if @variable_reference_map.has_key?(object)
|
17
|
+
@reference_id += 1
|
18
|
+
@variable_reference_map[object] = @reference_id
|
19
|
+
@reference_variable_map[@reference_id] = object
|
20
|
+
@reference_id
|
21
|
+
end
|
22
|
+
|
23
|
+
def get id
|
24
|
+
@reference_variable_map[id]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/readapt/server.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
require 'securerandom'
|
2
|
-
require 'stringio'
|
3
|
-
|
4
|
-
module Readapt
|
5
|
-
module Server
|
6
|
-
class << self
|
7
|
-
attr_accessor :target_in
|
8
|
-
attr_accessor :target_pid
|
9
|
-
end
|
10
|
-
|
11
|
-
def opening
|
12
|
-
Error.adapter = self
|
13
|
-
Output.adapter = self
|
14
|
-
end
|
15
|
-
|
16
|
-
def receiving data
|
17
|
-
Server.target_in.syswrite data
|
18
|
-
rescue Errno::EPIPE, IOError
|
19
|
-
close
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
1
|
+
require 'securerandom'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
module Readapt
|
5
|
+
module Server
|
6
|
+
class << self
|
7
|
+
attr_accessor :target_in
|
8
|
+
attr_accessor :target_pid
|
9
|
+
end
|
10
|
+
|
11
|
+
def opening
|
12
|
+
Error.adapter = self
|
13
|
+
Output.adapter = self
|
14
|
+
end
|
15
|
+
|
16
|
+
def receiving data
|
17
|
+
Server.target_in.syswrite data
|
18
|
+
rescue Errno::EPIPE, IOError
|
19
|
+
close
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/readapt/shell.rb
CHANGED
@@ -1,104 +1,104 @@
|
|
1
|
-
require 'thor'
|
2
|
-
require 'backport'
|
3
|
-
require 'open3'
|
4
|
-
require 'securerandom'
|
5
|
-
require 'socket'
|
6
|
-
|
7
|
-
module Readapt
|
8
|
-
class Shell < Thor
|
9
|
-
map %w[--version -v] => :version
|
10
|
-
|
11
|
-
desc "--version, -v", "Print the version"
|
12
|
-
def version
|
13
|
-
puts Readapt::VERSION
|
14
|
-
end
|
15
|
-
|
16
|
-
desc 'socket', 'Run a DAP server over TCP'
|
17
|
-
option :host, type: :string, aliases: :h, description: 'The server host', default: '127.0.0.1'
|
18
|
-
option :port, type: :numeric, aliases: :p, description: 'The server port', default: 1234
|
19
|
-
def socket
|
20
|
-
machine = Backport::Machine.new
|
21
|
-
machine.run do
|
22
|
-
prepare_machine machine
|
23
|
-
server = Backport::Server::Tcpip.new(host: options[:host], port: options[:port], adapter: Readapt::Server)
|
24
|
-
machine.prepare server
|
25
|
-
STDERR.puts "Readapt Debugger #{Readapt::VERSION} is listening HOST=#{options[:host]} PORT=#{options[:port]} PID=#{Process.pid}"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
map serve: :socket
|
29
|
-
|
30
|
-
desc 'stdio', 'Run a DAP server over STDIO'
|
31
|
-
def stdio
|
32
|
-
machine = Backport::Machine.new
|
33
|
-
machine.run do
|
34
|
-
prepare_machine machine
|
35
|
-
server = Backport::Server::Stdio.new(adapter: Readapt::Server)
|
36
|
-
machine.prepare server
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
desc 'target [PROCID]', 'Run a target process'
|
41
|
-
def target procid = nil
|
42
|
-
STDIN.binmode
|
43
|
-
STDOUT.binmode
|
44
|
-
STDERR.binmode
|
45
|
-
STDOUT.sync = true
|
46
|
-
STDERR.sync = true
|
47
|
-
Readapt::Adapter.procid = procid
|
48
|
-
machine = Backport::Machine.new
|
49
|
-
Signal.trap("INT") do
|
50
|
-
graceful_shutdown machine
|
51
|
-
end
|
52
|
-
Signal.trap("TERM") do
|
53
|
-
graceful_shutdown machine
|
54
|
-
end
|
55
|
-
machine.run do
|
56
|
-
debugger = Readapt::Debugger.new
|
57
|
-
Readapt::Adapter.host debugger
|
58
|
-
machine.prepare Backport::Server::Stdio.new(input: STDIN, output: STDERR, adapter: Readapt::Adapter)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
# @param machine [Backport::Machine]
|
65
|
-
# @return [void]
|
66
|
-
def prepare_machine machine
|
67
|
-
STDOUT.sync = true
|
68
|
-
STDERR.sync = true
|
69
|
-
Signal.trap("INT") do
|
70
|
-
graceful_shutdown machine
|
71
|
-
end
|
72
|
-
Signal.trap("TERM") do
|
73
|
-
graceful_shutdown machine
|
74
|
-
end
|
75
|
-
procid = SecureRandom.hex(8)
|
76
|
-
Readapt::Error.procid = procid
|
77
|
-
stdin, stdout, stderr, thr = Open3.popen3('ruby', $0, 'target', procid)
|
78
|
-
stdin.sync = true
|
79
|
-
stdout.sync = true
|
80
|
-
stderr.sync = true
|
81
|
-
stdin.binmode
|
82
|
-
Readapt::Server.target_in = stdin
|
83
|
-
Readapt::Server.target_pid = thr[:pid]
|
84
|
-
output = Backport::Server::Stdio.new(input: stdout, output: stdin, adapter: Readapt::Output)
|
85
|
-
error = Backport::Server::Stdio.new(input: stderr, output: stdin, adapter: Readapt::Error)
|
86
|
-
machine.prepare output
|
87
|
-
machine.prepare error
|
88
|
-
at_exit do
|
89
|
-
begin
|
90
|
-
Process.kill 'KILL', thr[:pid]
|
91
|
-
rescue Errno::ESRCH
|
92
|
-
# Ignore
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# @param machine [Backport::Machine]
|
98
|
-
# @return [void]
|
99
|
-
def graceful_shutdown machine
|
100
|
-
machine.stop
|
101
|
-
exit
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
1
|
+
require 'thor'
|
2
|
+
require 'backport'
|
3
|
+
require 'open3'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'socket'
|
6
|
+
|
7
|
+
module Readapt
|
8
|
+
class Shell < Thor
|
9
|
+
map %w[--version -v] => :version
|
10
|
+
|
11
|
+
desc "--version, -v", "Print the version"
|
12
|
+
def version
|
13
|
+
puts Readapt::VERSION
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'socket', 'Run a DAP server over TCP'
|
17
|
+
option :host, type: :string, aliases: :h, description: 'The server host', default: '127.0.0.1'
|
18
|
+
option :port, type: :numeric, aliases: :p, description: 'The server port', default: 1234
|
19
|
+
def socket
|
20
|
+
machine = Backport::Machine.new
|
21
|
+
machine.run do
|
22
|
+
prepare_machine machine
|
23
|
+
server = Backport::Server::Tcpip.new(host: options[:host], port: options[:port], adapter: Readapt::Server)
|
24
|
+
machine.prepare server
|
25
|
+
STDERR.puts "Readapt Debugger #{Readapt::VERSION} is listening HOST=#{options[:host]} PORT=#{options[:port]} PID=#{Process.pid}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
map serve: :socket
|
29
|
+
|
30
|
+
desc 'stdio', 'Run a DAP server over STDIO'
|
31
|
+
def stdio
|
32
|
+
machine = Backport::Machine.new
|
33
|
+
machine.run do
|
34
|
+
prepare_machine machine
|
35
|
+
server = Backport::Server::Stdio.new(adapter: Readapt::Server)
|
36
|
+
machine.prepare server
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
desc 'target [PROCID]', 'Run a target process'
|
41
|
+
def target procid = nil
|
42
|
+
STDIN.binmode
|
43
|
+
STDOUT.binmode
|
44
|
+
STDERR.binmode
|
45
|
+
STDOUT.sync = true
|
46
|
+
STDERR.sync = true
|
47
|
+
Readapt::Adapter.procid = procid
|
48
|
+
machine = Backport::Machine.new
|
49
|
+
Signal.trap("INT") do
|
50
|
+
graceful_shutdown machine
|
51
|
+
end
|
52
|
+
Signal.trap("TERM") do
|
53
|
+
graceful_shutdown machine
|
54
|
+
end
|
55
|
+
machine.run do
|
56
|
+
debugger = Readapt::Debugger.new
|
57
|
+
Readapt::Adapter.host debugger
|
58
|
+
machine.prepare Backport::Server::Stdio.new(input: STDIN, output: STDERR, adapter: Readapt::Adapter)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# @param machine [Backport::Machine]
|
65
|
+
# @return [void]
|
66
|
+
def prepare_machine machine
|
67
|
+
STDOUT.sync = true
|
68
|
+
STDERR.sync = true
|
69
|
+
Signal.trap("INT") do
|
70
|
+
graceful_shutdown machine
|
71
|
+
end
|
72
|
+
Signal.trap("TERM") do
|
73
|
+
graceful_shutdown machine
|
74
|
+
end
|
75
|
+
procid = SecureRandom.hex(8)
|
76
|
+
Readapt::Error.procid = procid
|
77
|
+
stdin, stdout, stderr, thr = Open3.popen3('ruby', $0, 'target', procid)
|
78
|
+
stdin.sync = true
|
79
|
+
stdout.sync = true
|
80
|
+
stderr.sync = true
|
81
|
+
stdin.binmode
|
82
|
+
Readapt::Server.target_in = stdin
|
83
|
+
Readapt::Server.target_pid = thr[:pid]
|
84
|
+
output = Backport::Server::Stdio.new(input: stdout, output: stdin, adapter: Readapt::Output)
|
85
|
+
error = Backport::Server::Stdio.new(input: stderr, output: stdin, adapter: Readapt::Error)
|
86
|
+
machine.prepare output
|
87
|
+
machine.prepare error
|
88
|
+
at_exit do
|
89
|
+
begin
|
90
|
+
Process.kill 'KILL', thr[:pid]
|
91
|
+
rescue Errno::ESRCH
|
92
|
+
# Ignore
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# @param machine [Backport::Machine]
|
98
|
+
# @return [void]
|
99
|
+
def graceful_shutdown machine
|
100
|
+
machine.stop
|
101
|
+
exit
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|