vmc 0.3.23 → 0.4.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
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