vmc 0.3.23 → 0.4.0.beta.1

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.
Files changed (60) hide show
  1. data/bin/vmc +11 -2
  2. data/vmc-ng/LICENSE +746 -0
  3. data/vmc-ng/Rakefile +11 -0
  4. data/vmc-ng/bin/vmc +14 -0
  5. data/vmc-ng/lib/vmc.rb +2 -0
  6. data/vmc-ng/lib/vmc/cli.rb +327 -0
  7. data/vmc-ng/lib/vmc/cli/app.rb +622 -0
  8. data/vmc-ng/lib/vmc/cli/better_help.rb +193 -0
  9. data/vmc-ng/lib/vmc/cli/command.rb +523 -0
  10. data/vmc-ng/lib/vmc/cli/dots.rb +133 -0
  11. data/vmc-ng/lib/vmc/cli/service.rb +122 -0
  12. data/vmc-ng/lib/vmc/cli/user.rb +72 -0
  13. data/vmc-ng/lib/vmc/constants.rb +10 -0
  14. data/vmc-ng/lib/vmc/detect.rb +64 -0
  15. data/vmc-ng/lib/vmc/errors.rb +17 -0
  16. data/vmc-ng/lib/vmc/plugin.rb +40 -0
  17. data/vmc-ng/lib/vmc/version.rb +3 -0
  18. data/{LICENSE → vmc/LICENSE} +0 -0
  19. data/{README.md → vmc/README.md} +1 -5
  20. data/{Rakefile → vmc/Rakefile} +0 -0
  21. data/vmc/bin/vmc +6 -0
  22. data/{caldecott_helper → vmc/caldecott_helper}/Gemfile +0 -0
  23. data/{caldecott_helper → vmc/caldecott_helper}/Gemfile.lock +0 -0
  24. data/{caldecott_helper → vmc/caldecott_helper}/server.rb +0 -0
  25. data/{config → vmc/config}/clients.yml +0 -0
  26. data/{config → vmc/config}/micro/offline.conf +0 -0
  27. data/{config → vmc/config}/micro/paths.yml +0 -0
  28. data/{config → vmc/config}/micro/refresh_ip.rb +0 -0
  29. data/{lib → vmc/lib}/cli.rb +0 -0
  30. data/{lib → vmc/lib}/cli/commands/admin.rb +0 -0
  31. data/{lib → vmc/lib}/cli/commands/apps.rb +0 -0
  32. data/{lib → vmc/lib}/cli/commands/base.rb +0 -0
  33. data/{lib → vmc/lib}/cli/commands/manifest.rb +0 -0
  34. data/{lib → vmc/lib}/cli/commands/micro.rb +0 -0
  35. data/{lib → vmc/lib}/cli/commands/misc.rb +0 -0
  36. data/{lib → vmc/lib}/cli/commands/services.rb +0 -0
  37. data/{lib → vmc/lib}/cli/commands/user.rb +2 -6
  38. data/{lib → vmc/lib}/cli/config.rb +0 -0
  39. data/{lib → vmc/lib}/cli/console_helper.rb +4 -14
  40. data/{lib → vmc/lib}/cli/core_ext.rb +0 -0
  41. data/{lib → vmc/lib}/cli/errors.rb +0 -0
  42. data/{lib → vmc/lib}/cli/frameworks.rb +1 -1
  43. data/{lib → vmc/lib}/cli/manifest_helper.rb +0 -0
  44. data/{lib → vmc/lib}/cli/runner.rb +0 -0
  45. data/{lib → vmc/lib}/cli/services_helper.rb +0 -0
  46. data/{lib → vmc/lib}/cli/tunnel_helper.rb +0 -0
  47. data/{lib → vmc/lib}/cli/usage.rb +0 -0
  48. data/{lib → vmc/lib}/cli/version.rb +1 -1
  49. data/{lib → vmc/lib}/cli/zip_util.rb +0 -0
  50. data/{lib → vmc/lib}/vmc.rb +0 -0
  51. data/{lib → vmc/lib}/vmc/client.rb +0 -0
  52. data/{lib → vmc/lib}/vmc/const.rb +0 -0
  53. data/{lib → vmc/lib}/vmc/micro.rb +0 -0
  54. data/{lib → vmc/lib}/vmc/micro/switcher/base.rb +0 -0
  55. data/{lib → vmc/lib}/vmc/micro/switcher/darwin.rb +0 -0
  56. data/{lib → vmc/lib}/vmc/micro/switcher/dummy.rb +0 -0
  57. data/{lib → vmc/lib}/vmc/micro/switcher/linux.rb +0 -0
  58. data/{lib → vmc/lib}/vmc/micro/switcher/windows.rb +0 -0
  59. data/{lib → vmc/lib}/vmc/micro/vmrun.rb +1 -11
  60. metadata +177 -93
@@ -0,0 +1,193 @@
1
+ module VMC
2
+ module BetterHelp
3
+ @@groups = []
4
+ @@tree = {}
5
+
6
+ def nothing_printable?(group, all = false)
7
+ group[:members].reject { |_, _, opts| !all && opts[:hidden] }.empty? &&
8
+ group[:children].all? { |g| nothing_printable?(g) }
9
+ end
10
+
11
+ def print_help_group(group, all = false, indent = 0)
12
+ return if nothing_printable?(group, all)
13
+
14
+ members = group[:members]
15
+
16
+ unless all
17
+ members = members.reject do |_, _, opts|
18
+ opts[:hidden]
19
+ end
20
+ end
21
+
22
+ members = members.collect do |cls, name, opts|
23
+ [cls, cls.tasks[name]]
24
+ end
25
+
26
+ i = " " * indent
27
+
28
+ print i
29
+ puts group[:description]
30
+
31
+ width = 0
32
+ members.each do |cls, t|
33
+ sub = find_subcommand_name(cls)
34
+ len = (sub ? sub.size + 1 : 0) + t.usage.size
35
+ if len > width
36
+ width = len
37
+ end
38
+ end
39
+
40
+ members.each do |cls, t|
41
+ sub = find_subcommand_name(cls)
42
+
43
+ print "#{i} "
44
+
45
+ label = sub ? "#{sub} " : ""
46
+ label << t.usage
47
+
48
+ print "#{label.ljust(width)}\t#{t.description}"
49
+
50
+ puts ""
51
+ end
52
+
53
+ puts "" unless members.empty?
54
+
55
+ group[:children].each do |group|
56
+ print_help_group(group, all, indent + 1)
57
+ end
58
+ end
59
+
60
+ def groups(*tree)
61
+ tree.each do |*args|
62
+ add_group(@@groups, @@tree, *args.first)
63
+ end
64
+ end
65
+
66
+ def add_group(groups, tree, name, desc, *subs)
67
+ members = []
68
+
69
+ meta = {:members => members, :children => []}
70
+ groups << meta
71
+
72
+ tree[name] = {:members => members, :children => {}}
73
+
74
+ meta[:description] = desc
75
+
76
+ subs.each do |*args|
77
+ add_group(meta[:children], tree[name][:children], *args.first)
78
+ end
79
+ end
80
+
81
+ def group(*names)
82
+ options =
83
+ if names.last.is_a? Hash
84
+ names.pop
85
+ else
86
+ {}
87
+ end
88
+
89
+ where = @@tree
90
+ top = true
91
+ names.each do |n|
92
+ where = where[:children] unless top
93
+
94
+ unless where
95
+ raise "unknown group: #{names.join("/")}"
96
+ end
97
+
98
+ where = where[n]
99
+
100
+ top = false
101
+ end
102
+
103
+ where[:members] << [self, @usage.split.first, options]
104
+ end
105
+
106
+ def subcommand_classes
107
+ @subcommand_classes ||= {}
108
+ end
109
+
110
+ def subcommand_names
111
+ @subcommand_names ||= {}
112
+ end
113
+
114
+ def subcommand(name, cls)
115
+ subcommand_classes[name] = cls
116
+ subcommand_names[cls] = name
117
+ super
118
+ end
119
+
120
+ def find_subcommand_name(cls)
121
+ found = subcommand_names[cls]
122
+ return found if found
123
+
124
+ if superclass.respond_to?(:find_subcommand_name) &&
125
+ found = superclass.find_subcommand_name(cls)
126
+ return found
127
+ end
128
+
129
+ subcommand_classes.each do |name, sub|
130
+ if found = sub.find_subcommand_name(cls)
131
+ return name + " " + found
132
+ end
133
+ end
134
+
135
+ nil
136
+ end
137
+
138
+ def find_subcommand(name)
139
+ found = subcommand_classes[name]
140
+ return found if found
141
+
142
+ if superclass.respond_to? :find_subcommand
143
+ superclass.find_subcommand(name)
144
+ else
145
+ nil
146
+ end
147
+ end
148
+
149
+ def task_help(shell, task_name)
150
+ if sub = find_subcommand(task_name)
151
+ sub.help(shell, true)
152
+ elsif t = all_tasks[task_name]
153
+ puts t.description
154
+ puts ""
155
+ puts "Usage: #{t.usage}"
156
+ puts ""
157
+ class_options_help(shell, nil => t.options.map { |_, o| o })
158
+ else
159
+ super
160
+ end
161
+ end
162
+
163
+ def help(shell, subcommand = false)
164
+ puts "Tasks:"
165
+
166
+ width = 0
167
+ @tasks.each do |_, t|
168
+ len = t.usage.size
169
+ if len > width
170
+ width = len
171
+ end
172
+ end
173
+
174
+ @tasks.each do |_, t|
175
+ print " "
176
+
177
+ print "#{t.usage.ljust(width)}\t#{t.description}"
178
+
179
+ puts ""
180
+ end
181
+
182
+ puts ""
183
+
184
+ class_options_help(shell)
185
+ end
186
+
187
+ def print_help_groups(all = false)
188
+ @@groups.each do |commands|
189
+ print_help_group(commands, all)
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,523 @@
1
+ require "thor"
2
+ require "interact"
3
+ require "yaml"
4
+
5
+ require "cfoundry"
6
+
7
+ require "vmc/constants"
8
+ require "vmc/errors"
9
+ require "vmc/cli/dots"
10
+ require "vmc/cli/better_help"
11
+
12
+
13
+ module VMC
14
+ module Interactive
15
+ include ::Interactive::Rewindable
16
+ include Dots
17
+
18
+ class InteractiveDefault
19
+ attr_reader :method
20
+
21
+ def initialize(query, cls, cmd, flag)
22
+ # here be dragons
23
+ #
24
+ # MRI has no Proc -> Lambda, so this is kind of the only way to work
25
+ # around Proc's "convenient" argument handling while keeping the
26
+ # blocks evaluated on the Command instance
27
+
28
+ @method = :"__interact_#{cmd}_#{flag}__"
29
+ cls.queries.send(:define_method, @method, &query)
30
+ end
31
+
32
+ def to_s
33
+ "(interaction)"
34
+ end
35
+ end
36
+
37
+ def force?
38
+ false
39
+ end
40
+
41
+ def ask(question, options = {})
42
+ if force? and options.key?(:default)
43
+ options[:default]
44
+ else
45
+ super
46
+ end
47
+ end
48
+
49
+ def list_choices(choices, options)
50
+ choices.each_with_index do |o, i|
51
+ puts "#{c(i + 1, :green)}: #{o}"
52
+ end
53
+ end
54
+
55
+ def input_state(options)
56
+ CFState.new(options)
57
+ end
58
+
59
+ def prompt(question, options)
60
+ value =
61
+ case options[:default]
62
+ when true
63
+ "y"
64
+ when false
65
+ "n"
66
+ when nil
67
+ ""
68
+ else
69
+ options[:default].to_s
70
+ end
71
+
72
+ print "#{question}"
73
+ print c("> ", :blue)
74
+
75
+ unless value.empty?
76
+ print "#{c(value, :black) + "\b" * value.size}"
77
+ end
78
+ end
79
+
80
+ def handler(which, state)
81
+ ans = state.answer
82
+ pos = state.position
83
+
84
+ if state.default?
85
+ if which.is_a?(Array) and which[0] == :key
86
+ # initial non-movement keypress clears default answer
87
+ clear_input(state)
88
+ else
89
+ # wipe away any coloring
90
+ redraw_input(state)
91
+ end
92
+
93
+ state.clear_default!
94
+ end
95
+
96
+ super
97
+
98
+ print "\n" if which == :enter
99
+ end
100
+
101
+ class CFState < Interactive::InputState
102
+ def initialize(options = {}, answer = nil, position = 0)
103
+ @options = options
104
+
105
+ if answer
106
+ @answer = answer
107
+ elsif options[:default]
108
+ case options[:default]
109
+ when true
110
+ @answer = "y"
111
+ when false
112
+ @answer = "n"
113
+ else
114
+ @answer = options[:default].to_s
115
+ end
116
+
117
+ @default = true
118
+ else
119
+ @answer = ""
120
+ end
121
+
122
+ @position = position
123
+ @done = false
124
+ end
125
+
126
+ def clear_default!
127
+ @default = false
128
+ end
129
+
130
+ def default?
131
+ @default
132
+ end
133
+ end
134
+ end
135
+
136
+ class Command < Thor
137
+ include Interactive
138
+ extend BetterHelp
139
+
140
+ class_option :proxy, :aliases => "-u", :desc => "Proxy user"
141
+
142
+ class_option :verbose,
143
+ :type => :boolean, :aliases => "-v", :desc => "Verbose"
144
+
145
+ class_option :force,
146
+ :type => :boolean, :aliases => "-f", :desc => "Force (no interaction)"
147
+
148
+ class_option :simple_output,
149
+ :type => :boolean, :desc => "Simplified output format."
150
+
151
+ class_option :script, :type => :boolean, :aliases => "-s",
152
+ :desc => "--simple-output and --force"
153
+
154
+ class_option :trace, :type => :boolean, :aliases => "-t",
155
+ :desc => "Show API requests and responses"
156
+
157
+ class_option :color, :type => :boolean, :desc => "Colored output"
158
+
159
+ def self.queries
160
+ return @queries if @queries
161
+
162
+ @queries = Module.new
163
+ include @queries
164
+
165
+ @queries
166
+ end
167
+
168
+ def self.flag(name, options = {}, &query)
169
+ if query
170
+ options[:default] ||=
171
+ InteractiveDefault.new(query, self, @usage.split.first, name)
172
+ end
173
+
174
+ method_option(name, options)
175
+ end
176
+
177
+ def self.callbacks_for(name)
178
+ cs = callbacks[name]
179
+ if superclass.respond_to? :callbacks
180
+ cs.merge superclass.callbacks_for(name)
181
+ else
182
+ cs
183
+ end
184
+ end
185
+
186
+ def self.callbacks
187
+ @callbacks ||= Hash.new do |h, name|
188
+ h[name] = Hash.new do |h, task|
189
+ h[task] = []
190
+ end
191
+ end
192
+ end
193
+
194
+ def self.add_callback(name, task, callback)
195
+ callbacks[name][task] << callback
196
+ end
197
+
198
+ def self.before(task, &callback)
199
+ add_callback(:before, task, callback)
200
+ end
201
+
202
+ def self.after(task, &callback)
203
+ add_callback(:after, task, callback)
204
+ end
205
+
206
+ def self.ensuring(task, &callback)
207
+ add_callback(:ensuring, task, callback)
208
+ end
209
+
210
+ def self.around(task, &callback)
211
+ add_callback(:around, task, callback)
212
+ end
213
+
214
+ private
215
+
216
+ def callbacks_for(what)
217
+ self.class.callbacks_for(what)
218
+ end
219
+
220
+ def passed_value(flag)
221
+ if (val = options[flag]) && \
222
+ !val.is_a?(VMC::Interactive::InteractiveDefault)
223
+ val
224
+ end
225
+ end
226
+
227
+ def inputs
228
+ @inputs ||= {}
229
+ end
230
+
231
+ def input(name, *args)
232
+ return inputs[name] if inputs.key?(name)
233
+
234
+ val = options[name]
235
+ inputs[name] =
236
+ if val.is_a?(VMC::Interactive::InteractiveDefault)
237
+ send(val.method, *args)
238
+ elsif val.respond_to? :to_proc
239
+ instance_exec(*args, &options[name])
240
+ else
241
+ options[name]
242
+ end
243
+ end
244
+
245
+ def forget(name)
246
+ @inputs.delete name
247
+ end
248
+
249
+ def script?
250
+ if options.key?("script")
251
+ options["script"]
252
+ else
253
+ !$stdout.tty?
254
+ end
255
+ end
256
+
257
+ def force?
258
+ if options.key?("force")
259
+ options["force"]
260
+ else
261
+ script?
262
+ end
263
+ end
264
+
265
+ def verbose?
266
+ options["verbose"]
267
+ end
268
+
269
+ def simple_output?
270
+ if options.key?("simple_output")
271
+ options["simple_output"]
272
+ else
273
+ script?
274
+ end
275
+ end
276
+
277
+ def color?
278
+ if options.key?("color")
279
+ options["color"]
280
+ else
281
+ !simple_output?
282
+ end
283
+ end
284
+
285
+ def err(msg, exit_status = 1)
286
+ if script?
287
+ $stderr.puts(msg)
288
+ else
289
+ puts c(msg, :red)
290
+ end
291
+
292
+ $exit_status = 1
293
+ end
294
+
295
+ def with_inputs(new)
296
+ return yield if !new || new.empty?
297
+
298
+ begin
299
+ orig = {}
300
+ new.each do |k, v|
301
+ orig[k] = inputs[k]
302
+ inputs[k] = v
303
+ end
304
+
305
+ yield
306
+ ensure
307
+ orig.each do |k, v|
308
+ if v.nil?
309
+ inputs.delete(k)
310
+ else
311
+ inputs[k] = v
312
+ end
313
+ end
314
+ end
315
+ end
316
+
317
+ def fail(msg)
318
+ raise UserError, msg
319
+ end
320
+
321
+ def invoke_task(task, args)
322
+ callbacks_for(:before)[task.name.to_sym].each do |c|
323
+ c.call
324
+ end
325
+
326
+ action = proc do |*given_args|
327
+ if inputs = given_args.first
328
+ with_inputs(inputs) do
329
+ task.run(self, args)
330
+ end
331
+ else
332
+ task.run(self, args)
333
+ end
334
+ end
335
+
336
+ callbacks_for(:around)[task.name.to_sym].each do |a|
337
+ before = action
338
+ action = proc do |*given_args|
339
+ if inputs = given_args.first
340
+ with_inputs(inputs) do
341
+ instance_exec(before, args, &a)
342
+ end
343
+ else
344
+ instance_exec(before, args, &a)
345
+ end
346
+ end
347
+ end
348
+
349
+ res = instance_exec(args, &action)
350
+
351
+ callbacks_for(:after)[task.name.to_sym].each do |c|
352
+ c.call
353
+ end
354
+
355
+ res
356
+ rescue Interrupt
357
+ $exit_status = 130
358
+ rescue Thor::Error
359
+ raise
360
+ rescue UserError => e
361
+ err e.message
362
+ rescue Exception => e
363
+ msg = e.class.name
364
+ msg << ": #{e}" unless e.to_s.empty?
365
+ err msg
366
+
367
+ ensure_config_dir
368
+
369
+ File.open(File.expand_path(VMC::CRASH_FILE), "w") do |f|
370
+ f.print "Time of crash:\n "
371
+ f.puts Time.now
372
+ f.puts ""
373
+ f.puts msg
374
+ f.puts ""
375
+
376
+ e.backtrace.each do |loc|
377
+ if loc =~ /\/gems\//
378
+ f.puts loc.sub(/.*\/gems\//, "")
379
+ else
380
+ f.puts loc.sub(File.expand_path("../../../..", __FILE__) + "/", "")
381
+ end
382
+ end
383
+ end
384
+ ensure
385
+ callbacks_for(:ensuring)[task.name.to_sym].each do |c|
386
+ c.call
387
+ end
388
+ end
389
+ public :invoke_task
390
+
391
+ def sane_target_url(url)
392
+ unless url =~ /^https?:\/\//
393
+ url = "http://#{url}"
394
+ end
395
+
396
+ url.gsub(/\/$/, "")
397
+ end
398
+
399
+ def target_file
400
+ one_of(VMC::TARGET_FILE, VMC::OLD_TARGET_FILE)
401
+ end
402
+
403
+ def tokens_file
404
+ one_of(VMC::TOKENS_FILE, VMC::OLD_TOKENS_FILE)
405
+ end
406
+
407
+ def one_of(*paths)
408
+ paths.each do |p|
409
+ exp = File.expand_path(p)
410
+ return exp if File.exist? exp
411
+ end
412
+
413
+ paths.first
414
+ end
415
+
416
+ def client_target
417
+ File.read(target_file).chomp
418
+ end
419
+
420
+ def ensure_config_dir
421
+ config = File.expand_path(VMC::CONFIG_DIR)
422
+ Dir.mkdir(config) unless File.exist? config
423
+ end
424
+
425
+ def set_target(url)
426
+ ensure_config_dir
427
+
428
+ File.open(File.expand_path(VMC::TARGET_FILE), "w") do |f|
429
+ f.write(sane_target_url(url))
430
+ end
431
+
432
+ @client = nil
433
+ end
434
+
435
+ def tokens
436
+ new_toks = File.expand_path(VMC::TOKENS_FILE)
437
+ old_toks = File.expand_path(VMC::OLD_TOKENS_FILE)
438
+
439
+ if File.exist? new_toks
440
+ YAML.load_file(new_toks)
441
+ elsif File.exist? old_toks
442
+ JSON.load(File.read(old_toks))
443
+ else
444
+ {}
445
+ end
446
+ end
447
+
448
+ def client_token
449
+ tokens[client_target]
450
+ end
451
+
452
+ def save_tokens(ts)
453
+ ensure_config_dir
454
+
455
+ File.open(File.expand_path(VMC::TOKENS_FILE), "w") do |io|
456
+ YAML.dump(ts, io)
457
+ end
458
+ end
459
+
460
+ def save_token(token)
461
+ ts = tokens
462
+ ts[client_target] = token
463
+ save_tokens(ts)
464
+ end
465
+
466
+ def remove_token
467
+ ts = tokens
468
+ ts.delete client_target
469
+ save_tokens(ts)
470
+ end
471
+
472
+ def client
473
+ return @client if @client
474
+
475
+ @client = CFoundry::Client.new(client_target, client_token)
476
+ @client.proxy = options[:proxy]
477
+ @client.trace = options[:trace]
478
+ @client
479
+ end
480
+
481
+ def usage(used, limit)
482
+ "#{b(human_size(used))} of #{b(human_size(limit, 0))}"
483
+ end
484
+
485
+ def percentage(num, low = 50, mid = 70)
486
+ color =
487
+ if num <= low
488
+ :green
489
+ elsif num <= mid
490
+ :yellow
491
+ else
492
+ :red
493
+ end
494
+
495
+ c(format("%.1f\%", num), color)
496
+ end
497
+
498
+ def megabytes(str)
499
+ if str =~ /T$/i
500
+ str.to_i * 1024 * 1024
501
+ elsif str =~ /G$/i
502
+ str.to_i * 1024
503
+ elsif str =~ /M$/i
504
+ str.to_i
505
+ elsif str =~ /K$/i
506
+ str.to_i / 1024
507
+ end
508
+ end
509
+
510
+ def human_size(num, precision = 1)
511
+ sizes = ["G", "M", "K"]
512
+ sizes.each.with_index do |suf, i|
513
+ pow = sizes.size - i
514
+ unit = 1024 ** pow
515
+ if num >= unit
516
+ return format("%.#{precision}f%s", num / unit, suf)
517
+ end
518
+ end
519
+
520
+ format("%.#{precision}fB", num)
521
+ end
522
+ end
523
+ end