cf 0.1.5 → 0.6.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. data/LICENSE +1277 -30
  2. data/Rakefile +12 -1
  3. data/bin/cf +0 -3
  4. data/lib/cf.rb +6 -0
  5. data/lib/cf/cli.rb +389 -190
  6. data/lib/cf/cli/app/app.rb +45 -0
  7. data/lib/cf/cli/app/apps.rb +99 -0
  8. data/lib/cf/cli/app/base.rb +90 -0
  9. data/lib/cf/cli/app/crashes.rb +42 -0
  10. data/lib/cf/cli/app/delete.rb +95 -0
  11. data/lib/cf/cli/app/deprecated.rb +11 -0
  12. data/lib/cf/cli/app/env.rb +78 -0
  13. data/lib/cf/cli/app/files.rb +137 -0
  14. data/lib/cf/cli/app/health.rb +26 -0
  15. data/lib/cf/cli/app/instances.rb +53 -0
  16. data/lib/cf/cli/app/logs.rb +76 -0
  17. data/lib/cf/cli/app/push.rb +105 -0
  18. data/lib/cf/cli/app/push/create.rb +149 -0
  19. data/lib/cf/cli/app/push/interactions.rb +94 -0
  20. data/lib/cf/cli/app/push/sync.rb +64 -0
  21. data/lib/cf/cli/app/rename.rb +35 -0
  22. data/lib/cf/cli/app/restart.rb +20 -0
  23. data/lib/cf/cli/app/scale.rb +69 -0
  24. data/lib/cf/cli/app/start.rb +143 -0
  25. data/lib/cf/cli/app/stats.rb +67 -0
  26. data/lib/cf/cli/app/stop.rb +27 -0
  27. data/lib/cf/cli/domain/base.rb +8 -0
  28. data/lib/cf/cli/domain/domains.rb +40 -0
  29. data/lib/cf/cli/domain/map.rb +55 -0
  30. data/lib/cf/cli/domain/unmap.rb +56 -0
  31. data/lib/cf/cli/help.rb +15 -0
  32. data/lib/cf/cli/interactive.rb +105 -0
  33. data/lib/cf/cli/organization/base.rb +12 -0
  34. data/lib/cf/cli/organization/create.rb +32 -0
  35. data/lib/cf/cli/organization/delete.rb +73 -0
  36. data/lib/cf/cli/organization/org.rb +45 -0
  37. data/lib/cf/cli/organization/orgs.rb +35 -0
  38. data/lib/cf/cli/organization/rename.rb +36 -0
  39. data/lib/cf/cli/route/base.rb +8 -0
  40. data/lib/cf/cli/route/map.rb +70 -0
  41. data/lib/cf/cli/route/routes.rb +26 -0
  42. data/lib/cf/cli/route/unmap.rb +62 -0
  43. data/lib/cf/cli/service/base.rb +8 -0
  44. data/lib/cf/cli/service/bind.rb +44 -0
  45. data/lib/cf/cli/service/create.rb +107 -0
  46. data/lib/cf/cli/service/delete.rb +82 -0
  47. data/lib/cf/cli/service/rename.rb +35 -0
  48. data/lib/cf/cli/service/service.rb +40 -0
  49. data/lib/cf/cli/service/services.rb +99 -0
  50. data/lib/cf/cli/service/unbind.rb +38 -0
  51. data/lib/cf/cli/space/base.rb +19 -0
  52. data/lib/cf/cli/space/create.rb +63 -0
  53. data/lib/cf/cli/space/delete.rb +95 -0
  54. data/lib/cf/cli/space/rename.rb +39 -0
  55. data/lib/cf/cli/space/space.rb +64 -0
  56. data/lib/cf/cli/space/spaces.rb +55 -0
  57. data/lib/cf/cli/space/switch.rb +16 -0
  58. data/lib/cf/cli/start/base.rb +93 -0
  59. data/lib/cf/cli/start/colors.rb +13 -0
  60. data/lib/cf/cli/start/info.rb +124 -0
  61. data/lib/cf/cli/start/login.rb +94 -0
  62. data/lib/cf/cli/start/logout.rb +17 -0
  63. data/lib/cf/cli/start/target.rb +69 -0
  64. data/lib/cf/cli/start/target_interactions.rb +37 -0
  65. data/lib/cf/cli/start/targets.rb +16 -0
  66. data/lib/cf/cli/user/base.rb +29 -0
  67. data/lib/cf/cli/user/create.rb +39 -0
  68. data/lib/cf/cli/user/passwd.rb +43 -0
  69. data/lib/cf/cli/user/register.rb +42 -0
  70. data/lib/cf/cli/user/users.rb +32 -0
  71. data/lib/cf/constants.rb +10 -7
  72. data/lib/cf/detect.rb +113 -48
  73. data/lib/cf/errors.rb +17 -0
  74. data/lib/cf/plugin.rb +28 -12
  75. data/lib/cf/spacing.rb +89 -0
  76. data/lib/cf/spec_helper.rb +1 -0
  77. data/lib/cf/test_support.rb +6 -0
  78. data/lib/cf/version.rb +1 -1
  79. data/spec/assets/hello-sinatra/Gemfile +3 -0
  80. data/spec/assets/hello-sinatra/Gemfile.lock +17 -0
  81. data/spec/assets/hello-sinatra/config.ru +3 -0
  82. data/spec/assets/hello-sinatra/fat-cat-makes-app-larger.png +0 -0
  83. data/spec/assets/hello-sinatra/main.rb +6 -0
  84. data/spec/assets/specker_runner/specker_runner_input.rb +6 -0
  85. data/spec/assets/specker_runner/specker_runner_pause.rb +5 -0
  86. data/spec/cf/cli/app/base_spec.rb +17 -0
  87. data/spec/cf/cli/app/delete_spec.rb +188 -0
  88. data/spec/cf/cli/app/instances_spec.rb +65 -0
  89. data/spec/cf/cli/app/push/create_spec.rb +661 -0
  90. data/spec/cf/cli/app/push_spec.rb +369 -0
  91. data/spec/cf/cli/app/rename_spec.rb +104 -0
  92. data/spec/cf/cli/app/scale_spec.rb +75 -0
  93. data/spec/cf/cli/app/start_spec.rb +208 -0
  94. data/spec/cf/cli/app/stats_spec.rb +68 -0
  95. data/spec/cf/cli/domain/map_spec.rb +130 -0
  96. data/spec/cf/cli/domain/unmap_spec.rb +69 -0
  97. data/spec/cf/cli/organization/orgs_spec.rb +108 -0
  98. data/spec/cf/cli/organization/rename_spec.rb +113 -0
  99. data/spec/cf/cli/route/map_spec.rb +121 -0
  100. data/spec/cf/cli/route/unmap_spec.rb +155 -0
  101. data/spec/cf/cli/service/bind_spec.rb +25 -0
  102. data/spec/cf/cli/service/delete_spec.rb +22 -0
  103. data/spec/cf/cli/service/rename_spec.rb +105 -0
  104. data/spec/cf/cli/service/service_spec.rb +23 -0
  105. data/spec/cf/cli/service/unbind_spec.rb +25 -0
  106. data/spec/cf/cli/space/create_spec.rb +93 -0
  107. data/spec/cf/cli/space/rename_spec.rb +102 -0
  108. data/spec/cf/cli/space/spaces_spec.rb +104 -0
  109. data/spec/cf/cli/space/switch_space_spec.rb +55 -0
  110. data/spec/cf/cli/start/info_spec.rb +160 -0
  111. data/spec/cf/cli/start/login_spec.rb +142 -0
  112. data/spec/cf/cli/start/logout_spec.rb +50 -0
  113. data/spec/cf/cli/start/target_spec.rb +123 -0
  114. data/spec/cf/cli/user/create_spec.rb +54 -0
  115. data/spec/cf/cli/user/passwd_spec.rb +102 -0
  116. data/spec/cf/cli/user/register_spec.rb +140 -0
  117. data/spec/cf/cli_spec.rb +442 -0
  118. data/spec/cf/detect_spec.rb +54 -0
  119. data/spec/console_app_specker/console_app_specker_matchers_spec.rb +173 -0
  120. data/spec/console_app_specker/specker_runner_spec.rb +167 -0
  121. data/spec/features/account_lifecycle_spec.rb +85 -0
  122. data/spec/features/login_spec.rb +66 -0
  123. data/spec/features/push_flow_spec.rb +125 -0
  124. data/spec/features/switching_targets_spec.rb +32 -0
  125. data/spec/spec_helper.rb +72 -0
  126. data/spec/support/command_helper.rb +81 -0
  127. data/spec/support/config_helper.rb +15 -0
  128. data/spec/support/console_app_specker_matchers.rb +86 -0
  129. data/spec/support/fake_home_dir.rb +55 -0
  130. data/spec/support/interact_helper.rb +29 -0
  131. data/spec/support/shared_examples/errors.rb +40 -0
  132. data/spec/support/shared_examples/input.rb +14 -0
  133. data/spec/support/specker_runner.rb +80 -0
  134. data/spec/support/tracking_expector.rb +71 -0
  135. metadata +427 -66
  136. data/lib/cf/cli/app.rb +0 -595
  137. data/lib/cf/cli/command.rb +0 -444
  138. data/lib/cf/cli/dots.rb +0 -133
  139. data/lib/cf/cli/service.rb +0 -112
  140. data/lib/cf/cli/user.rb +0 -71
@@ -1,595 +0,0 @@
1
- require "cf/cli/command"
2
- require "cf/detect"
3
-
4
- module CF
5
- class App < Command
6
- MEM_CHOICES = ["64M", "128M", "256M", "512M"]
7
-
8
- desc "apps", "List your applications"
9
- def apps
10
- apps =
11
- with_progress("Getting applications") do
12
- client.apps
13
- end
14
-
15
- if apps.empty? and !simple_output?
16
- puts ""
17
- puts "No applications."
18
- return
19
- end
20
-
21
- apps.each.with_index do |a, num|
22
- display_app(a)
23
- end
24
- end
25
-
26
- desc "health ...APPS", "Get application health"
27
- def health(*names)
28
- apps =
29
- with_progress("Getting application health") do
30
- names.collect do |n|
31
- [n, app_status(client.app(n))]
32
- end
33
- end
34
-
35
- apps.each do |name, status|
36
- unless simple_output?
37
- puts ""
38
- print "#{c(name, :blue)}: "
39
- end
40
-
41
- puts status
42
- end
43
- end
44
-
45
- desc "stop [APP]", "Stop an application"
46
- def stop(name)
47
- with_progress("Stopping #{c(name, :blue)}") do |s|
48
- app = client.app(name)
49
-
50
- unless app.exists?
51
- s.fail do
52
- err "Unknown application."
53
- end
54
- end
55
-
56
- if app.stopped?
57
- s.skip do
58
- err "Application is not running."
59
- end
60
- end
61
-
62
- app.stop!
63
- end
64
- end
65
-
66
- desc "start [APP]", "Start an application"
67
- flag(:debug_mode)
68
- def start(name)
69
- app = client.app(name)
70
-
71
- unless app.exists?
72
- err "Unknown application."
73
- return
74
- end
75
-
76
- switch_mode(app, input(:debug_mode))
77
-
78
- with_progress("Starting #{c(name, :blue)}") do |s|
79
- if app.running?
80
- s.skip do
81
- err "Already started."
82
- return
83
- end
84
- end
85
-
86
- app.start!
87
- end
88
-
89
- check_application(app)
90
-
91
- if app.debug_mode && !simple_output?
92
- puts ""
93
- instances(name)
94
- end
95
- end
96
-
97
- desc "restart [APP]", "Stop and start an application"
98
- flag(:debug_mode)
99
- def restart(name)
100
- stop(name)
101
- start(name)
102
- end
103
-
104
- desc "delete [APP]", "Delete an application"
105
- flag(:really) { |name, color = :blue|
106
- force? || ask("Really delete #{c(name, color)}?", :default => false)
107
- }
108
- flag(:name) { |names|
109
- ask("Delete which application?", :choices => names)
110
- }
111
- flag(:all, :default => false)
112
- def delete(name = nil)
113
- if input(:all)
114
- return unless input(:really, "ALL APPS", :red)
115
-
116
- with_progress("Deleting all applications") do
117
- client.apps.collect(&:delete!)
118
- end
119
-
120
- return
121
- end
122
-
123
- unless name
124
- apps = client.apps
125
- return err "No applications." if apps.empty?
126
-
127
- name = input(:name, apps.collect(&:name))
128
- end
129
-
130
- return unless input(:really, name)
131
-
132
- with_progress("Deleting #{c(name, :blue)}") do
133
- client.app(name).delete!
134
- end
135
- ensure
136
- forget(:really)
137
- end
138
-
139
- desc "instances [APP]", "List an app's instances"
140
- def instances(name)
141
- instances =
142
- with_progress("Getting instances for #{c(name, :blue)}") do
143
- client.app(name).instances
144
- end
145
-
146
- instances.each do |i|
147
- if simple_output?
148
- puts i.index
149
- else
150
- puts ""
151
- display_instance(i)
152
- end
153
- end
154
- end
155
-
156
- desc "files [APP] [PATH]", "Examine an app's files"
157
- def files(name, path = "/")
158
- files =
159
- with_progress("Getting file listing") do
160
- client.app(name).files(*path.split("/"))
161
- end
162
-
163
- puts "" unless simple_output?
164
-
165
- files.each do |file|
166
- puts file
167
- end
168
- end
169
-
170
- desc "file [APP] [PATH]", "Print out an app's file contents"
171
- def file(name, path = "/")
172
- file =
173
- with_progress("Getting file contents") do
174
- client.app(name).file(*path.split("/"))
175
- end
176
-
177
- puts "" unless simple_output?
178
-
179
- print file
180
- end
181
-
182
- desc "logs [APP]", "Print out an app's logs"
183
- flag(:instance, :type => :numeric, :default => 0)
184
- def logs(name)
185
- app = client.app(name)
186
- unless app.exists?
187
- err "Unknown application."
188
- return
189
- end
190
-
191
- instances =
192
- if input(:instance) == "all"
193
- app.instances
194
- else
195
- app.instances.select { |i| i.index == input(:instance) }
196
- end
197
-
198
- if instances.empty?
199
- if input(:instance) == "all"
200
- err "No instances found."
201
- else
202
- err "Instance #{name} \##{input(:instance)} not found."
203
- end
204
-
205
- return
206
- end
207
-
208
- instances.each do |i|
209
- logs =
210
- with_progress(
211
- "Getting logs for " +
212
- c(name, :blue) + " " +
213
- c("\##{i.index}", :yellow)) do
214
- i.files("logs")
215
- end
216
-
217
- puts "" unless simple_output?
218
-
219
- logs.each do |log|
220
- body =
221
- with_progress("Reading " + b(log.join("/"))) do
222
- i.file(*log)
223
- end
224
-
225
- puts body
226
- puts "" unless body.empty?
227
- end
228
- end
229
- end
230
-
231
- desc "push [NAME]", "Push an application, syncing changes if it exists"
232
- flag(:name) { ask("Name") }
233
- flag(:path) {
234
- ask("Push from...", :default => ".")
235
- }
236
- flag(:url) { |name, target|
237
- ask("URL", :default => "#{name}.#{target}")
238
- }
239
- flag(:memory) {
240
- ask("Memory Limit",
241
- :choices => MEM_CHOICES,
242
-
243
- # TODO: base this on framework choice
244
- :default => "64M")
245
- }
246
- flag(:instances) {
247
- ask("Instances", :default => 1)
248
- }
249
- flag(:framework) { |choices, default|
250
- ask("Framework", :choices => choices, :default => default)
251
- }
252
- flag(:runtime) { |choices|
253
- ask("Runtime", :choices => choices)
254
- }
255
- flag(:start, :default => true)
256
- flag(:restart, :default => true)
257
- def push(name = nil)
258
- path = File.expand_path(input(:path))
259
-
260
- name ||= input(:name)
261
-
262
- detector = Detector.new(client, path)
263
- frameworks = detector.all_frameworks
264
- detected, default = detector.frameworks
265
-
266
- app = client.app(name)
267
-
268
- if app.exists?
269
- upload_app(app, path)
270
- restart(app.name) if input(:restart)
271
- return
272
- end
273
-
274
- app.total_instances = input(:instances)
275
-
276
- domain = client.target.sub(/^https?:\/\/api\.(.+)\/?/, '\1')
277
- app.urls = [input(:url, name, domain)]
278
-
279
- framework = input(:framework, ["other"] + detected.keys, default)
280
- if framework == "other"
281
- forget(:framework)
282
- framework = input(:framework, frameworks.keys)
283
- end
284
-
285
- framework_runtimes =
286
- frameworks[framework]["runtimes"].collect do |k|
287
- "#{k["name"]} (#{k["description"]})"
288
- end
289
-
290
- # TODO: include descriptions
291
- runtime = input(:runtime, framework_runtimes).split.first
292
-
293
- app.framework = framework
294
- app.runtime = runtime
295
-
296
- app.memory = megabytes(input(:memory))
297
-
298
- with_progress("Creating #{c(name, :blue)}") do
299
- app.create!
300
- end
301
-
302
- begin
303
- upload_app(app, path)
304
- rescue
305
- err "Upload failed. Try again with 'vmc push'."
306
- raise
307
- end
308
-
309
- start(name) if input(:start)
310
- end
311
-
312
- desc "update", "DEPRECATED", :hide => true
313
- def update(*args)
314
- err "The 'update' command is no longer used; use 'push' instead."
315
- end
316
-
317
- desc "stats [APP]", "Display application instance status"
318
- def stats(name)
319
- stats =
320
- with_progress("Getting stats") do
321
- client.app(name).stats
322
- end
323
-
324
- stats.sort_by { |k, _| k }.each do |idx, info|
325
- stats = info["stats"]
326
- usage = stats["usage"]
327
- puts ""
328
- puts "instance #{c("#" + idx, :blue)}:"
329
- print " cpu: #{percentage(usage["cpu"])} of"
330
- puts " #{b(stats["cores"])} cores"
331
- puts " memory: #{usage(usage["mem"] * 1024, stats["mem_quota"])}"
332
- puts " disk: #{usage(usage["disk"], stats["disk_quota"])}"
333
- end
334
- end
335
-
336
- desc "scale [APP]", "Update the instances/memory limit for an application"
337
- flag(:instances, :type => :numeric) { |default|
338
- ask("Instances", :default => default)
339
- }
340
- flag(:memory) { |default|
341
- ask("Memory Limit",
342
- :default => human_size(default * 1024 * 1024, 0),
343
- :choices => MEM_CHOICES)
344
- }
345
- def scale(name)
346
- app = client.app(name)
347
-
348
- instances = passed_value(:instances)
349
- memory = passed_value(:memory)
350
-
351
- unless instances || memory
352
- instances = input(:instances, app.total_instances)
353
- memory = input(:memory, app.memory)
354
- end
355
-
356
- with_progress("Scaling #{c(name, :blue)}") do
357
- app.total_instances = instances.to_i if instances
358
- app.memory = megabytes(memory) if memory
359
- app.update!
360
- end
361
- end
362
-
363
- desc "map NAME URL", "Add a URL mapping for an app"
364
- def map(name, url)
365
- simple = url.sub(/^https?:\/\/(.*)\/?/i, '\1')
366
-
367
- with_progress("Updating #{c(name, :blue)}") do
368
- app = client.app(name)
369
- app.urls << simple
370
- app.update!
371
- end
372
- end
373
-
374
- desc "unmap NAME URL", "Remove a URL mapping from an app"
375
- def unmap(name, url)
376
- simple = url.sub(/^https?:\/\/(.*)\/?/i, '\1')
377
-
378
- with_progress("Updating #{c(name, :blue)}") do |s|
379
- app = client.app(name)
380
-
381
- unless app.urls.delete(simple)
382
- s.fail do
383
- err "URL #{url} is not mapped to this application."
384
- return
385
- end
386
- end
387
-
388
- app.update!
389
- end
390
- end
391
-
392
- class Env < Command
393
- VALID_NAME = /^[a-zA-Za-z_][[:alnum:]_]*$/
394
-
395
- desc "set [APP] [NAME] [VALUE]", "Set an environment variable"
396
- def set(appname, name, value)
397
- app = client.app(appname)
398
- unless name =~ VALID_NAME
399
- err "Invalid variable name; must match #{VALID_NAME.inspect}"
400
- return
401
- end
402
-
403
- unless app.exists?
404
- err "Unknown application."
405
- return
406
- end
407
-
408
- with_progress("Updating #{c(app.name, :blue)}") do
409
- app.update!("env" =>
410
- app.env.reject { |v|
411
- v.start_with?("#{name}=")
412
- }.push("#{name}=#{value}"))
413
- end
414
- end
415
-
416
- desc "unset [APP] [NAME]", "Remove an environment variable"
417
- def unset(appname, name)
418
- app = client.app(appname)
419
-
420
- unless app.exists?
421
- err "Unknown application."
422
- return
423
- end
424
-
425
- with_progress("Updating #{c(app.name, :blue)}") do
426
- app.update!("env" =>
427
- app.env.reject { |v|
428
- v.start_with?("#{name}=")
429
- })
430
- end
431
- end
432
-
433
- desc "list [APP]", "Show all environment variables set for an app"
434
- def list(appname)
435
- vars =
436
- with_progress("Getting variables") do |s|
437
- app = client.app(appname)
438
-
439
- unless app.exists?
440
- s.fail do
441
- err "Unknown application."
442
- return
443
- end
444
- end
445
-
446
- app.env
447
- end
448
-
449
- puts "" unless simple_output?
450
-
451
- vars.each do |pair|
452
- name, val = pair.split("=", 2)
453
- puts "#{c(name, :blue)}: #{val}"
454
- end
455
- end
456
- end
457
-
458
- desc "env SUBCOMMAND ...ARGS", "Manage application environment variables"
459
- subcommand "env", Env
460
-
461
- private
462
-
463
- def upload_app(app, path)
464
- with_progress("Uploading #{c(app.name, :blue)}") do
465
- app.upload(path)
466
- end
467
- end
468
-
469
- # set app debug mode, ensuring it's valid, and shutting it down
470
- def switch_mode(app, mode)
471
- mode = nil if mode == "none"
472
-
473
- return false if app.debug_mode == mode
474
-
475
- if mode.nil?
476
- with_progress("Removing debug mode") do
477
- app.debug_mode = nil
478
- app.stop! if app.running?
479
- end
480
-
481
- return true
482
- end
483
-
484
- with_progress("Switching mode to #{c(mode, :blue)}") do |s|
485
- runtimes = client.system_runtimes
486
- modes = runtimes[app.runtime]["debug_modes"] || []
487
- if modes.include?(mode)
488
- app.debug_mode = mode
489
- app.stop! if app.running?
490
- true
491
- else
492
- s.fail do
493
- err "Unknown mode '#{mode}'; available: #{modes.inspect}"
494
- false
495
- end
496
- end
497
- end
498
- end
499
-
500
- APP_CHECK_LIMIT = 60
501
-
502
- def check_application(app)
503
- with_progress("Checking #{c(app.name, :blue)}") do |s|
504
- if app.debug_mode == "suspend"
505
- s.skip do
506
- puts "Application is in suspended debugging mode."
507
- puts "It will wait for you to attach to it before starting."
508
- end
509
- end
510
-
511
- seconds = 0
512
- until app.healthy?
513
- sleep 1
514
- seconds += 1
515
- if seconds == APP_CHECK_LIMIT
516
- s.give_up do
517
- err "Application failed to start."
518
- # TODO: print logs
519
- end
520
- end
521
- end
522
- end
523
- end
524
-
525
- # choose the right color for app/instance state
526
- def state_color(s)
527
- case s
528
- when "STARTING"
529
- :blue
530
- when "STARTED", "RUNNING"
531
- :green
532
- when "DOWN"
533
- :red
534
- when "FLAPPING"
535
- :magenta
536
- when "N/A"
537
- :cyan
538
- else
539
- :yellow
540
- end
541
- end
542
-
543
- def app_status(a)
544
- health = a.health
545
-
546
- if a.debug_mode == "suspend" && health == "0%"
547
- c("suspended", :yellow)
548
- else
549
- c(health.downcase, state_color(health))
550
- end
551
- end
552
-
553
- def display_app(a)
554
- if simple_output?
555
- puts a.name
556
- return
557
- end
558
-
559
- puts ""
560
-
561
- status = app_status(a)
562
-
563
- print "#{c(a.name, :blue)}: #{status}"
564
-
565
- unless a.total_instances == 1
566
- print ", #{b(a.total_instances)} instances"
567
- end
568
-
569
- puts ""
570
-
571
- unless a.urls.empty?
572
- puts " urls: #{a.urls.collect { |u| b(u) }.join(", ")}"
573
- end
574
-
575
- unless a.services.empty?
576
- puts " services: #{a.services.collect { |s| b(s) }.join(", ")}"
577
- end
578
- end
579
-
580
- def display_instance(i)
581
- print "instance #{c("\##{i.index}", :blue)}: "
582
- puts "#{b(c(i.state.downcase, state_color(i.state)))} "
583
-
584
- puts " started: #{c(i.since.strftime("%F %r"), :cyan)}"
585
-
586
- if d = i.debugger
587
- puts " debugger: port #{c(d["port"], :blue)} at #{c(d["ip"], :blue)}"
588
- end
589
-
590
- if c = i.console
591
- puts " console: port #{b(c["port"])} at #{b(c["ip"])}"
592
- end
593
- end
594
- end
595
- end