dockerun 0.3.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -11
  3. data/Rakefile +0 -2
  4. data/Rakefile.bak +8 -0
  5. data/dockerspec.sample +104 -0
  6. data/{dockerun.gemspec → dockerun.gemspec.bak} +20 -22
  7. data/exe/dockerun +8 -115
  8. data/lib/dockerun/cli/command.rb +133 -0
  9. data/lib/dockerun/cli/command_factory.rb +313 -0
  10. data/lib/dockerun/cli/command_result.rb +67 -0
  11. data/lib/dockerun/cli/delete_container.rb +55 -0
  12. data/lib/dockerun/cli/delete_image.rb +99 -0
  13. data/lib/dockerun/cli/run.rb +39 -0
  14. data/lib/dockerun/cli/user_info.rb +39 -0
  15. data/lib/dockerun/cli_engine.rb +104 -0
  16. data/lib/dockerun/config.rb +40 -70
  17. data/lib/dockerun/context/rubygems.rb +142 -0
  18. data/lib/dockerun/dfile.rb +204 -0
  19. data/lib/dockerun/docker_cli.rb +124 -0
  20. data/lib/dockerun/dsl.rb +291 -0
  21. data/lib/dockerun/version.rb +1 -1
  22. data/lib/dockerun.rb +31 -24
  23. data/sig/dockerun.rbs +4 -0
  24. metadata +62 -73
  25. data/.release_history.yml +0 -56
  26. data/Dockerfile.dockerun +0 -38
  27. data/Gemfile +0 -15
  28. data/Gemfile.lock +0 -94
  29. data/bin/console +0 -15
  30. data/bin/setup +0 -8
  31. data/lib/dockerun/bundler_helper.rb +0 -25
  32. data/lib/dockerun/cli_prompt.rb +0 -18
  33. data/lib/dockerun/command/dockerun.rb +0 -30
  34. data/lib/dockerun/command/init.rb +0 -79
  35. data/lib/dockerun/command/remove_container.rb +0 -99
  36. data/lib/dockerun/command/reset_image.rb +0 -107
  37. data/lib/dockerun/command/run.rb +0 -221
  38. data/lib/dockerun/command/run_new_container.rb +0 -94
  39. data/lib/dockerun/command/run_new_image.rb +0 -89
  40. data/lib/dockerun/command/stop_container.rb +0 -90
  41. data/lib/dockerun/docker_command_factory_helper.rb +0 -19
  42. data/lib/dockerun/docker_container_helper.rb +0 -204
  43. data/lib/dockerun/docker_image_helper.rb +0 -381
  44. data/lib/dockerun/template/general_template_writer.rb +0 -14
  45. data/lib/dockerun/template/jruby_template_writer.rb +0 -24
  46. data/lib/dockerun/template/template_engine.rb +0 -27
  47. data/lib/dockerun/template/template_writer.rb +0 -102
  48. data/lib/dockerun/user_info.rb +0 -37
  49. data/template/Dockerfile_general.erb +0 -41
  50. data/template/setup_ruby_devenv.rb.erb +0 -22
@@ -0,0 +1,313 @@
1
+
2
+ require 'erb'
3
+
4
+ require_relative 'command'
5
+ require_relative 'user_info'
6
+
7
+ module Dockerun
8
+ module Cli
9
+ class CommandFactory
10
+ include TR::CondUtils
11
+
12
+ def build_image(name = "", opts = { }, &block)
13
+
14
+ opts = { } if opts.nil?
15
+ cmd = []
16
+ cmd << DockerCli.docker_exe
17
+ cmd << "build"
18
+ if not_empty?(name)
19
+ cmd << "-t #{name}"
20
+ end
21
+
22
+ if not_empty?(opts[:dockerfile])
23
+ cmd << "-f #{opts[:dockerfile]}"
24
+ end
25
+
26
+ root = opts[:context_root]
27
+ root = "." if is_empty?(root)
28
+ cmd << root
29
+
30
+ logger.debug "Build Image : #{cmd.join(" ")}"
31
+ Command.new(cmd)
32
+
33
+ end # build_image
34
+
35
+
36
+ def find_image(name, tag = "", opts = { })
37
+ name = "" if name.nil?
38
+ cmd = []
39
+ cmd << DockerCli.docker_exe
40
+ cmd << "images"
41
+ cmd << "-q"
42
+ if not_empty?(tag)
43
+ cmd << "#{name}:#{tag}"
44
+ else
45
+ cmd << name
46
+ end
47
+
48
+ logger.debug "Find image: #{cmd.join(" ")}"
49
+
50
+ Command.new(cmd)
51
+ end # find_image
52
+
53
+ def delete_image(name, tag = "", opts = { })
54
+
55
+ if not_empty?(name)
56
+
57
+ cmd = []
58
+ cmd << DockerCli.docker_exe
59
+ cmd << "rmi"
60
+ if not_empty?(tag)
61
+ cmd << "#{name}:#{tag}"
62
+ else
63
+ cmd << name
64
+ end
65
+
66
+ logger.debug "Delete image: #{cmd.join(" ")}"
67
+ Command.new(cmd)
68
+
69
+ else
70
+ raise Error, "Name is required for delete operation"
71
+ end
72
+
73
+ end # delete_image
74
+
75
+
76
+ def find_running_container(name, opts = { })
77
+
78
+ raise Error, "Name is mandatory" if is_empty?(name)
79
+
80
+ cmd = []
81
+ cmd << DockerCli.docker_exe
82
+ cmd << "ps"
83
+ cmd << "-q"
84
+ cmd << "-f"
85
+ cmd << "name=\"#{name}\""
86
+
87
+ logger.debug "Find container: #{cmd.join(" ")}"
88
+
89
+ Command.new(cmd)
90
+
91
+ end
92
+
93
+ # Find from container even if it is already stopped
94
+ def find_from_all_container(name, opts = { })
95
+ raise Error, "Name is required" if is_empty?(name)
96
+ cmd = []
97
+ cmd << DockerCli.docker_exe
98
+ cmd << "ps"
99
+ # return all info instead of only the container ID
100
+ #cmd << "-a"
101
+ cmd << "-aq"
102
+ cmd << "-f"
103
+ # From little testing seems the command by default already support regex formatting
104
+ # So can use the regex marker to get exact match
105
+ # e.g. if want exact match, pass in ^#{name}\z
106
+ cmd << "name=\"#{name}\""
107
+
108
+ logger.debug "Find from all container: #{cmd.join(" ")}"
109
+ Command.new(cmd)
110
+ end
111
+
112
+
113
+ def find_container_names_by_image_name(image_name, opts = { })
114
+
115
+ raise Error, "Image name is mandatory" if is_empty?(image_name)
116
+
117
+ cmd = []
118
+ cmd << DockerCli.docker_exe
119
+ cmd << "ps"
120
+ cmd << "-a" if opts[:all_containers] == true
121
+ cmd << "-f"
122
+ cmd << "ancestor=\"#{image_name}\""
123
+ cmd << "--format \"{{.Names}}\""
124
+
125
+ logger.debug "Find container by image name: #{cmd.join(" ")}"
126
+
127
+ Command.new(cmd)
128
+
129
+ end
130
+
131
+
132
+ #
133
+ # Create container from image directly
134
+ # e.g. > docker run -it <image> "/bin/bash"
135
+ #
136
+ def create_container_from_image(image, opts = { })
137
+ opts = {} if opts.nil?
138
+ cmd = []
139
+ cmd << DockerCli.docker_exe
140
+ cmd << "run"
141
+ cmd << "-i" if opts[:interactive] == true
142
+ cmd << "-t" if opts[:tty] == true
143
+ cmd << "-d" if opts[:detached] == true
144
+ cmd << "--rm" if opts[:del] == true
145
+ if not (opts[:container_name].nil? or opts[:container_name].empty?)
146
+ cmd << "--name \"#{opts[:container_name]}\""
147
+ end
148
+
149
+ cmd << process_mount(opts)
150
+ cmd << process_port(opts)
151
+
152
+ if opts[:match_user] == true
153
+ ui = UserInfo.user_info
154
+ gi = UserInfo.group_info
155
+ cmd << "-u #{ui[:uid]}:#{gi[:gid]}"
156
+ end
157
+
158
+ cmd << image
159
+
160
+ if not_empty?(opts[:command])
161
+ cmd << "\"#{opts[:command]}\""
162
+ end
163
+
164
+ interactive = false
165
+ interactive = true if opts[:interactive] or opts[:tty]
166
+
167
+ logger.debug "Run Container from Image : #{cmd.join(" ")}"
168
+ Command.new(cmd, (interactive ? true : false))
169
+ end # run_container_from_image
170
+
171
+ def start_container(container, opts = { })
172
+
173
+ opts = {} if opts.nil?
174
+ cmd = []
175
+ cmd << DockerCli.docker_exe
176
+ cmd << "container"
177
+ cmd << "start"
178
+ cmd << container
179
+
180
+ logger.debug "Start Container : #{cmd.join(" ")}"
181
+ Command.new(cmd)
182
+ end
183
+
184
+ def attach_container(container, opts = { })
185
+
186
+ opts = {} if opts.nil?
187
+ cmd = []
188
+ cmd << DockerCli.docker_exe
189
+ cmd << "container"
190
+ cmd << "attach"
191
+ cmd << container
192
+
193
+ logger.debug "Attach Container : #{cmd.join(" ")}"
194
+ # this is a bit difficult to juggle
195
+ # it depending on the previous docker configuration
196
+ # but to be save, just open up a new terminal
197
+ Command.new(cmd, true)
198
+ end
199
+
200
+
201
+ def stop_container(container, opts = { })
202
+
203
+ cmd = []
204
+ cmd << DockerCli.docker_exe
205
+ cmd << "container"
206
+ cmd << "stop"
207
+ cmd << container
208
+
209
+ logger.debug "Stop Container : #{cmd.join(" ")}"
210
+ Command.new(cmd)
211
+ end
212
+
213
+
214
+ def delete_container(container, opts = { })
215
+
216
+ cmd = []
217
+ cmd << DockerCli.docker_exe
218
+ cmd << "container"
219
+ cmd << "rm"
220
+ cmd << container
221
+
222
+ logger.debug "Delete Container : #{cmd.join(" ")}"
223
+ Command.new(cmd)
224
+ end
225
+
226
+
227
+ def run_command_in_running_container(container, command, opts = { })
228
+ cmd = []
229
+ cmd << DockerCli.docker_exe
230
+ cmd << "container"
231
+ cmd << "exec"
232
+
233
+ isTty = false
234
+ isInteractive = false
235
+ if not_empty?(opts[:tty]) and opts[:tty] == true
236
+ cmd << "-t"
237
+ isTty = true
238
+ end
239
+ if not_empty?(opts[:interactive]) and opts[:interactive] == true
240
+ cmd << "-i"
241
+ isInteractive = true
242
+ end
243
+
244
+ cmd << container
245
+
246
+ if is_empty?(command)
247
+ cmd << "/bin/bash --login"
248
+ else
249
+ cmd << command
250
+ end
251
+
252
+ logger.debug "Run command in running container : #{cmd.join(" ")}"
253
+ Command.new(cmd, ((isTty or isInteractive) ? true : false))
254
+ end # container_prompt
255
+
256
+
257
+ private
258
+ # expecting :mounts => { "/dir/local" => "/dir/inside/docker" }
259
+ def process_mount(opts)
260
+ if not_empty?(opts[:mounts]) #not (opts[:mounts].nil? or opts[:mounts].empty?)
261
+ m = opts[:mounts]
262
+ if m.is_a?(Hash)
263
+ res = []
264
+ m.each do |local, docker|
265
+ res << "-v #{local}:#{docker}"
266
+ end
267
+ res.join(" ")
268
+ end
269
+ else
270
+ ""
271
+ end
272
+
273
+ end # process_mount
274
+
275
+ def process_port(opts)
276
+ if not_empty?(opts[:ports]) #not (opts[:ports].nil? or opts[:ports].empty?)
277
+ po = opts[:ports]
278
+ res = []
279
+ if po.is_a?(Hash)
280
+ po.each do |host, docker|
281
+ res << "-p #{host}:#{docker}"
282
+ end
283
+ end
284
+ #po = [po] if not po.is_a?(Array)
285
+ #po.each do |e|
286
+ # # 1st is port on host
287
+ # # 2nd is port inside container
288
+ # res << "-p #{e.keys.first}:#{e.values.first}"
289
+ #end
290
+ res.join(" ")
291
+ else
292
+ ""
293
+ end
294
+
295
+ end
296
+
297
+ def logger
298
+ Dockerun.logger(:cmdFact)
299
+ end
300
+
301
+ def build_add_user_script
302
+ path = File.join(File.dirname(__FILE__),"..","..","..","scripts","create_user.sh.erb")
303
+ if File.exist?(path)
304
+ ui = UserInfo.user_info
305
+ gi = UserInfo.group_info
306
+
307
+ ERB.new(File.read(path)).result_with_hash({ user_group_id: gi[:gid], user_group_name: gi[:group_name], user_id: ui[:uid], user_login: ui[:login] })
308
+ end
309
+ end
310
+
311
+ end
312
+ end
313
+ end
@@ -0,0 +1,67 @@
1
+
2
+ require 'toolrack'
3
+
4
+ module Dockerun
5
+
6
+ module Cli
7
+
8
+ class CommandResult
9
+ include TR::CondUtils
10
+
11
+ attr_reader :out, :err, :result
12
+ def initialize(result, out, err)
13
+ @result = result
14
+ @out = out
15
+ @err = err
16
+ end
17
+
18
+ def is_out_stream_empty?
19
+ is_empty?(@out)
20
+ end
21
+
22
+ def is_err_stream_empty?
23
+ is_empty?(@err)
24
+ end
25
+
26
+ def out_stream
27
+ @out.join("\n")
28
+ end
29
+
30
+ def err_stream
31
+ @err.join("\n")
32
+ end
33
+
34
+ def failed?
35
+ if @result.nil?
36
+ true
37
+ else
38
+ @result.failed?
39
+ end
40
+ end
41
+
42
+ def success?
43
+ not failed?
44
+ end
45
+ alias_method :successful?, :success?
46
+
47
+ def each_output_line(&block)
48
+ out_stream.each_line(&block)
49
+ end
50
+
51
+ def each_err_lines(&block)
52
+ err_stream.each_line(&block)
53
+ end
54
+
55
+ def output_lines
56
+ out_stream.lines
57
+ end
58
+
59
+ def err_lines
60
+ err_stream.lines
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,55 @@
1
+
2
+ require_relative 'command_factory'
3
+
4
+ module Dockerun
5
+ module Cli
6
+ class DSLProxy
7
+ include DSL
8
+ end
9
+
10
+ class DeleteContainer
11
+
12
+ def start
13
+ begin
14
+ pmt.puts " Dockerun version #{Dockerun::VERSION}".yellow
15
+ pmt.puts " Operational : Delete Container"
16
+ delete_container
17
+ rescue TTY::Reader::InputInterrupt
18
+ end
19
+ end
20
+
21
+ def delete_container
22
+ selSpec = CliEngine.select_spec
23
+ cont = File.read(selSpec)
24
+ proxy = DSLProxy.new
25
+ proxy.set_dry_run_mode
26
+ proxy.instance_eval(cont)
27
+
28
+ skip = pmt.no?(" Delete container named '#{proxy.container_name}'?")
29
+ if not skip
30
+ cf.stop_container(proxy.container_name).run
31
+ res = cf.delete_container(proxy.container_name).run
32
+ if res.success?
33
+ pmt.puts " Container '#{proxy.container_name}' deleted".green
34
+ else
35
+ pmt.puts " Container '#{proxy.container_name}' deletion failed. Error was : #{res.err_lines.join("\n")}".red
36
+ end
37
+ else
38
+ pmt.puts " Container deletion of name '#{proxy.container_name}' aborted.".yellow
39
+ end
40
+ end
41
+
42
+ def pmt
43
+ CliEngine.pmt
44
+ end
45
+
46
+ def cf
47
+ if @_cf.nil?
48
+ @_cf = CommandFactory.new
49
+ end
50
+ @_cf
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,99 @@
1
+
2
+ require_relative 'command_factory'
3
+
4
+ module Dockerun
5
+ module Cli
6
+ class DSLProxy
7
+ include DSL
8
+ end
9
+
10
+ class DeleteImage
11
+ include TR::CondUtils
12
+
13
+ def start
14
+ begin
15
+ pmt.puts " Dockerun version #{Dockerun::VERSION}".yellow
16
+ pmt.puts " Operational : Delete Image"
17
+ delete_image
18
+ rescue TTY::Reader::InputInterrupt
19
+ end
20
+ end
21
+
22
+ def delete_image
23
+ selSpec = CliEngine.select_spec
24
+ cont = File.read(selSpec)
25
+ proxy = DSLProxy.new
26
+ proxy.set_dry_run_mode
27
+ proxy.instance_eval(cont)
28
+
29
+ res = cf.find_image(proxy.image_name).run
30
+ if res.success?
31
+ if not_empty?(res.output_lines)
32
+
33
+ skip = pmt.no?(" Delete image named '#{proxy.image_name}'?")
34
+ if not skip
35
+ res = cf.find_container_names_by_image_name(proxy.image_name, all_containers: true).run
36
+ raise Error, "Failed to extract container name by image name '#{proxy.image_name}'" if not res.success?
37
+
38
+ if not_empty?(res.output_lines)
39
+ cont = []
40
+ cnt = 0
41
+ res.output_lines.each do |l|
42
+ cont << " #{cnt += 1}. #{l}"
43
+ end
44
+ skip = pmt.no?(" All the containers shall be deleted prior to image '#{proxy.image_name}' deletion. Proceed?\n#{cont.join("\n")}")
45
+ if not skip
46
+ res.output_lines.each do |ci|
47
+ cf.stop_container(ci).run
48
+ cf.delete_container(ci).run
49
+ end
50
+
51
+ res = cf.delete_image(proxy.image_name).run
52
+ if res.success?
53
+ pmt.puts " Image '#{proxy.image_name}' deleted".green
54
+ else
55
+ raise Error, " Image '#{proxy.image_name}' deletion failed. Error was : #{res.err_lines.join("\n")}"
56
+ end
57
+
58
+ else
59
+ pmt.puts " Delete of image '#{proxy.image_name}' aborted".yellow
60
+ end
61
+
62
+ else
63
+ res = cf.delete_image(proxy.image_name).run
64
+ if res.success?
65
+ pmt.puts " Image '#{proxy.image_name}' deleted".green
66
+ else
67
+ raise Error, " Image '#{proxy.image_name}' deletion failed. Error was : #{res.err_lines.join("\n")}"
68
+ end
69
+
70
+ end
71
+
72
+ else
73
+ pmt.puts " Delete of image '#{proxy.image_name}' aborted".yellow
74
+
75
+ end
76
+
77
+ else
78
+ pmt.puts " Image '#{proxy.image_name}' does not exist".green
79
+ end
80
+
81
+ else
82
+ pmt.puts " Failed to find image '#{proxy.image_name}'. Error was : #{res.err_lines.join("\n")}"
83
+ end
84
+ end
85
+
86
+ def pmt
87
+ CliEngine.pmt
88
+ end
89
+
90
+ def cf
91
+ if @_cf.nil?
92
+ @_cf = CommandFactory.new
93
+ end
94
+ @_cf
95
+ end
96
+
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,39 @@
1
+
2
+ require 'tty/prompt'
3
+ require 'colorize'
4
+
5
+ module Dockerun
6
+ module Cli
7
+ class Run
8
+ #include TR::ArgUtils
9
+ include DSL
10
+
11
+ def start
12
+ begin
13
+ pmt.puts " Dockerun version #{Dockerun::VERSION}".yellow
14
+ pmt.puts " Operational : Run Spec"
15
+ load_spec
16
+ rescue TTY::Reader::InputInterrupt
17
+ end
18
+ end
19
+
20
+
21
+ private
22
+ def load_spec
23
+ selSpec = CliEngine.select_spec
24
+ pmt.puts " Loading spec '#{selSpec}"
25
+ cont = File.read(selSpec)
26
+ self.instance_eval(cont)
27
+ go if not is_go_done?
28
+ end
29
+
30
+ def pmt
31
+ if @_pmt.nil?
32
+ @_pmt = TTY::Prompt.new
33
+ end
34
+ @_pmt
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+
2
+ require 'etc'
3
+
4
+ module Dockerun
5
+ module Cli
6
+
7
+ module UserInfo
8
+ include TR::CondUtils
9
+
10
+ def self.user_info(login = nil)
11
+ login = Etc.getlogin if is_empty?(login)
12
+ res = { login: login }
13
+ begin
14
+ res[:uid] = Etc.getpwnam(login).uid
15
+ rescue Exception => ex
16
+ res[:uid] = nil
17
+ end
18
+ res
19
+ end
20
+
21
+ def self.group_info(login = nil)
22
+ login = Etc.getlogin if is_empty?(login)
23
+ res = { }
24
+ begin
25
+ gnm = Etc.getgrnam(login)
26
+ res[:group_name] = gnm.name
27
+ res[:gid] = gnm.gid
28
+ rescue Exception => ex
29
+ p ex
30
+ res[:group_name] = ""
31
+ res[:gid] = nil
32
+ end
33
+ res
34
+ end
35
+
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,104 @@
1
+
2
+ require 'tty/prompt'
3
+ require_relative 'cli/run'
4
+ require_relative 'cli/delete_container'
5
+ require_relative 'cli/delete_image'
6
+
7
+ module Dockerun
8
+ class CliEngine
9
+ include TR::ArgUtils
10
+
11
+ arg_spec do
12
+ opt "i", "Initialize sample dockerspec at current directory" do
13
+ init
14
+ end
15
+ opt_alias "i", "init"
16
+
17
+ opt "r", "Run the dockerspec" do
18
+ run
19
+ end
20
+ opt_alias "r","run"
21
+
22
+ opt "dc", "Delete container" do
23
+ delete_container
24
+ end
25
+
26
+ opt "di", "Delete image and its associated container(s)" do
27
+ delete_image
28
+ end
29
+
30
+ opt 'clean', "Clean generated Dockerfile and temporary files" do
31
+ clean_env
32
+ end
33
+
34
+ opt 'help', "Command help" do
35
+ print_help
36
+ end
37
+
38
+ end
39
+
40
+ def print_help
41
+ pmt = self.class.pmt
42
+ pmt.puts ""
43
+ pmt.puts " Dockerun version #{Dockerun::VERSION}".magenta
44
+ pmt.puts ""
45
+ pmt.puts " Supported options : "
46
+ self.class.arg_options.each do |key, val|
47
+ pmt.puts " #{key}\t\t#{val[:desc]}"
48
+ end
49
+ pmt.puts ""
50
+ end
51
+
52
+ def self.select_spec
53
+ sel = Dir.entries(Dir.getwd).sort
54
+ default = sel.select { |e| (e =~ /^dockerspec/) != nil }
55
+ selSpec = pmt.select(" Please select the dockerspec to proceed : ", filter: true, default: default.first) do |m|
56
+ sel.each do |s|
57
+ next if sel == "." or sel == ".." or File.directory?(s)
58
+ m.choice s, File.expand_path(s)
59
+ end
60
+ end
61
+
62
+ selSpec
63
+ end
64
+
65
+
66
+ def init
67
+ template = File.join(File.dirname(__FILE__),"..","..","dockerspec.sample")
68
+ if File.exist?(template)
69
+ FileUtils.cp template, File.join(Dir.getwd, "dockerspec.sample")
70
+ end
71
+ end
72
+
73
+ def run
74
+ r = Dockerun::Cli::Run.new
75
+ r.start
76
+ end
77
+
78
+ def delete_container
79
+ d = Dockerun::Cli::DeleteContainer.new
80
+ d.start
81
+ end
82
+
83
+ def delete_image
84
+ d = Dockerun::Cli::DeleteImage.new
85
+ d.start
86
+ end
87
+
88
+ def clean_env
89
+ Dir.glob("Dockerfile-*").each do |f|
90
+ FileUtils.rm(f)
91
+ end
92
+ FileUtils.rm("script_for_gem.sh") if File.exist?("script_for_gem.sh")
93
+ self.class.pmt.puts " Generated Dockerfile-* and script_for_gem.sh is deleted".green
94
+ end
95
+
96
+ def self.pmt
97
+ if @_pmt.nil?
98
+ @_pmt = TTY::Prompt.new
99
+ end
100
+ @_pmt
101
+ end
102
+
103
+ end
104
+ end