vmc 0.3.13.beta.5 → 0.3.13
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.
- data/lib/cli/commands/apps.rb +12 -1
- data/lib/cli/commands/base.rb +7 -2
- data/lib/cli/core_ext.rb +0 -328
- data/lib/cli/runner.rb +5 -1
- data/lib/cli/version.rb +1 -1
- metadata +22 -11
data/lib/cli/commands/apps.rb
CHANGED
@@ -388,7 +388,6 @@ module VMC::Cli::Command
|
|
388
388
|
|
389
389
|
# check if we have hit our app limit
|
390
390
|
check_app_limit
|
391
|
-
|
392
391
|
# check memsize here for capacity
|
393
392
|
if memswitch && !no_start
|
394
393
|
check_has_capacity_for(mem_choice_to_quota(memswitch) * instances)
|
@@ -572,6 +571,17 @@ module VMC::Cli::Command
|
|
572
571
|
err "Can't deploy applications from staging directory: [#{Dir.tmpdir}]"
|
573
572
|
end
|
574
573
|
|
574
|
+
def check_unreachable_links
|
575
|
+
path = Dir.pwd
|
576
|
+
files = Dir.glob("#{path}/**/*", File::FNM_DOTMATCH)
|
577
|
+
unreachable_paths = files.select { |f|
|
578
|
+
File.symlink? f and !File.expand_path(File.readlink(f)).include? path
|
579
|
+
} if files
|
580
|
+
if unreachable_paths.length > 0
|
581
|
+
err "Can't deploy application containing links '#{unreachable_paths}' that reach outside its root '#{path}'"
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
575
585
|
def upload_app_bits(appname, path)
|
576
586
|
display 'Uploading Application:'
|
577
587
|
|
@@ -586,6 +596,7 @@ module VMC::Cli::Command
|
|
586
596
|
if war_file = Dir.glob('*.war').first
|
587
597
|
VMC::Cli::ZipUtil.unpack(war_file, explode_dir)
|
588
598
|
else
|
599
|
+
check_unreachable_links
|
589
600
|
FileUtils.mkdir(explode_dir)
|
590
601
|
files = Dir.glob('{*,.[^\.]*}')
|
591
602
|
# Do not process .git files
|
data/lib/cli/commands/base.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
1
|
require 'rubygems'
|
2
|
+
require 'interact'
|
3
3
|
require 'terminal-table/import'
|
4
4
|
|
5
5
|
module VMC::Cli
|
@@ -7,6 +7,9 @@ module VMC::Cli
|
|
7
7
|
module Command
|
8
8
|
|
9
9
|
class Base
|
10
|
+
include Interactive
|
11
|
+
disable_rewind
|
12
|
+
|
10
13
|
attr_reader :no_prompt, :prompt_ok
|
11
14
|
|
12
15
|
def initialize(options={})
|
@@ -20,7 +23,9 @@ module VMC::Cli
|
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
23
|
-
|
26
|
+
# Inject a client to help in testing.
|
27
|
+
def client(cli=nil)
|
28
|
+
@client ||= cli
|
24
29
|
return @client if @client
|
25
30
|
@client = VMC::Client.new(target_url, auth_token)
|
26
31
|
@client.trace = VMC::Cli::Config.trace if VMC::Cli::Config.trace
|
data/lib/cli/core_ext.rb
CHANGED
@@ -68,334 +68,6 @@ module VMCExtensions
|
|
68
68
|
return sprintf("%.#{prec}fM", size/(1024.0*1024.0)) if size < (1024*1024*1024)
|
69
69
|
return sprintf("%.#{prec}fG", size/(1024.0*1024.0*1024.0))
|
70
70
|
end
|
71
|
-
|
72
|
-
# general-purpose interaction
|
73
|
-
#
|
74
|
-
# `question' is the prompt (without ": " at the end)
|
75
|
-
# `options' is a hash containing:
|
76
|
-
# :input - the input source (defaults to STDIN)
|
77
|
-
# :default - the default value, also used to attempt type conversion
|
78
|
-
# of the answer (e.g. numeric/boolean)
|
79
|
-
# :choices - a list of strings to choose from
|
80
|
-
# :indexed - whether to allow choosing from `:choices' by their index,
|
81
|
-
# best for when there are many choices
|
82
|
-
# :echo - a string to echo when showing the input;
|
83
|
-
# used for things like censoring password inpt
|
84
|
-
# :callback - a block used to override certain actions
|
85
|
-
#
|
86
|
-
# takes 4 arguments:
|
87
|
-
# action: the event, e.g. :up or [:key, X] where X is a
|
88
|
-
# string containing a single character
|
89
|
-
# answer: the current answer to the question; you'll
|
90
|
-
# probably mutate this
|
91
|
-
# position: the current offset from the start of the
|
92
|
-
# answer string, e.g. when typing in the middle
|
93
|
-
# of the input, this will be where you insert
|
94
|
-
# characters
|
95
|
-
# echo: the :echo option above, may be nil
|
96
|
-
#
|
97
|
-
# the block should return the updated `position', or nil if
|
98
|
-
# it didn't handle the event
|
99
|
-
def ask(question, options = {})
|
100
|
-
default = options[:default]
|
101
|
-
choices = options[:choices]
|
102
|
-
indexed = options[:indexed]
|
103
|
-
callback = options[:callback]
|
104
|
-
input = options[:input] || STDIN
|
105
|
-
echo = options[:echo]
|
106
|
-
|
107
|
-
if choices
|
108
|
-
VMCExtensions.ask_choices(input, question, default, choices, indexed, echo, &callback)
|
109
|
-
else
|
110
|
-
VMCExtensions.ask_default(input, question, default, echo, &callback)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
ESCAPES = {
|
115
|
-
"[A" => :up, "H" => :up,
|
116
|
-
"[B" => :down, "P" => :down,
|
117
|
-
"[C" => :right, "M" => :right,
|
118
|
-
"[D" => :left, "K" => :left,
|
119
|
-
"[3~" => :delete, "S" => :delete,
|
120
|
-
"[H" => :home, "G" => :home,
|
121
|
-
"[F" => :end, "O" => :end
|
122
|
-
}
|
123
|
-
|
124
|
-
def handle_action(which, ans, pos, echo = nil)
|
125
|
-
if block_given?
|
126
|
-
res = yield which, ans, pos, echo
|
127
|
-
return res unless res.nil?
|
128
|
-
end
|
129
|
-
|
130
|
-
case which
|
131
|
-
when :up
|
132
|
-
# nothing
|
133
|
-
|
134
|
-
when :down
|
135
|
-
# nothing
|
136
|
-
|
137
|
-
when :tab
|
138
|
-
# nothing
|
139
|
-
|
140
|
-
when :right
|
141
|
-
unless pos == ans.size
|
142
|
-
display censor(ans[pos .. pos], echo), false
|
143
|
-
return pos + 1
|
144
|
-
end
|
145
|
-
|
146
|
-
when :left
|
147
|
-
unless pos == 0
|
148
|
-
display "\b", false
|
149
|
-
return pos - 1
|
150
|
-
end
|
151
|
-
|
152
|
-
when :delete
|
153
|
-
unless pos == ans.size
|
154
|
-
ans.slice!(pos, 1)
|
155
|
-
if WINDOWS
|
156
|
-
rest = ans[pos .. -1]
|
157
|
-
display(censor(rest, echo) + " \b" + ("\b" * rest.size), false)
|
158
|
-
else
|
159
|
-
display("\e[P", false)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
when :home
|
164
|
-
display("\b" * pos, false)
|
165
|
-
return 0
|
166
|
-
|
167
|
-
when :end
|
168
|
-
display(censor(ans[pos .. -1], echo), false)
|
169
|
-
return ans.size
|
170
|
-
|
171
|
-
when :backspace
|
172
|
-
if pos > 0
|
173
|
-
ans.slice!(pos - 1, 1)
|
174
|
-
|
175
|
-
if WINDOWS
|
176
|
-
rest = ans[pos - 1 .. -1]
|
177
|
-
display("\b" + censor(rest, echo) + " \b" + ("\b" * rest.size), false)
|
178
|
-
else
|
179
|
-
display("\b\e[P", false)
|
180
|
-
end
|
181
|
-
|
182
|
-
return pos - 1
|
183
|
-
end
|
184
|
-
|
185
|
-
when :interrupt
|
186
|
-
raise Interrupt.new
|
187
|
-
|
188
|
-
when :eof
|
189
|
-
return false if ans.empty?
|
190
|
-
|
191
|
-
when :kill_word
|
192
|
-
if pos > 0
|
193
|
-
start = /[^\s]*\s*$/ =~ ans[0 .. pos]
|
194
|
-
length = pos - start
|
195
|
-
ans.slice!(start, length)
|
196
|
-
display("\b" * length + " " * length + "\b" * length, false)
|
197
|
-
return start
|
198
|
-
end
|
199
|
-
|
200
|
-
when Array
|
201
|
-
case which[0]
|
202
|
-
when :key
|
203
|
-
c = which[1]
|
204
|
-
rest = ans[pos .. -1]
|
205
|
-
|
206
|
-
ans.insert(pos, c)
|
207
|
-
|
208
|
-
display(censor(c + rest, echo) + ("\b" * rest.size), false)
|
209
|
-
|
210
|
-
return pos + 1
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
pos
|
215
|
-
end
|
216
|
-
|
217
|
-
def censor(str, with)
|
218
|
-
return str unless with
|
219
|
-
with * str.size
|
220
|
-
end
|
221
|
-
|
222
|
-
# ask a simple question, maybe with a default answer
|
223
|
-
#
|
224
|
-
# reads character-by-character, handling backspaces, and sending each
|
225
|
-
# character to a block if provided
|
226
|
-
def self.ask_default(input, question, default = nil, echo = nil, &callback)
|
227
|
-
while true
|
228
|
-
prompt(question, default)
|
229
|
-
|
230
|
-
ans = ""
|
231
|
-
pos = 0
|
232
|
-
escaped = false
|
233
|
-
escape_seq = ""
|
234
|
-
|
235
|
-
with_char_io(input) do
|
236
|
-
until pos == false or (c = get_character(input)) =~ /[\r\n]/
|
237
|
-
if c == "\e" || c == "\xE0"
|
238
|
-
escaped = true
|
239
|
-
elsif escaped
|
240
|
-
escape_seq << c
|
241
|
-
|
242
|
-
if cmd = ESCAPES[escape_seq]
|
243
|
-
pos = handle_action(cmd, ans, pos, echo, &callback)
|
244
|
-
escaped, escape_seq = false, ""
|
245
|
-
elsif ESCAPES.select { |k, v| k.start_with? escape_seq }.empty?
|
246
|
-
escaped, escape_seq = false, ""
|
247
|
-
end
|
248
|
-
elsif c == "\177" or c == "\b" # backspace
|
249
|
-
pos = handle_action(:backspace, ans, pos, echo, &callback)
|
250
|
-
elsif c == "\x01"
|
251
|
-
pos = handle_action(:home, ans, pos, echo, &callback)
|
252
|
-
elsif c == "\x03"
|
253
|
-
pos = handle_action(:interrupt, ans, pos, echo, &callback)
|
254
|
-
elsif c == "\x04"
|
255
|
-
pos = handle_action(:eof, ans, pos, echo, &callback)
|
256
|
-
elsif c == "\x05"
|
257
|
-
pos = handle_action(:end, ans, pos, echo, &callback)
|
258
|
-
elsif c == "\x17"
|
259
|
-
pos = handle_action(:kill_word, ans, pos, echo, &callback)
|
260
|
-
elsif c == "\t"
|
261
|
-
pos = handle_action(:tab, ans, pos, echo, &callback)
|
262
|
-
elsif c < " "
|
263
|
-
# ignore
|
264
|
-
else
|
265
|
-
pos = handle_action([:key, c], ans, pos, echo, &callback)
|
266
|
-
end
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
display "\n", false
|
271
|
-
|
272
|
-
if ans.empty?
|
273
|
-
return default unless default.nil?
|
274
|
-
else
|
275
|
-
return match_type(ans, default)
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
def self.ask_choices(input, question, default, choices, indexed = false, echo = nil, &callback)
|
281
|
-
msg = question.dup
|
282
|
-
|
283
|
-
if indexed
|
284
|
-
choices.each.with_index do |o, i|
|
285
|
-
say "#{i + 1}: #{o}"
|
286
|
-
end
|
287
|
-
else
|
288
|
-
msg << " (#{choices.collect(&:inspect).join ", "})"
|
289
|
-
end
|
290
|
-
|
291
|
-
while true
|
292
|
-
ans = ask_default(input, msg, default, echo, &callback)
|
293
|
-
|
294
|
-
matches = choices.select { |x| x.start_with? ans }
|
295
|
-
|
296
|
-
if matches.size == 1
|
297
|
-
return matches.first
|
298
|
-
elsif indexed and ans =~ /^\d+$/ and res = choices.to_a[ans.to_i - 1]
|
299
|
-
return res
|
300
|
-
elsif matches.size > 1
|
301
|
-
warn "Please disambiguate: #{matches.join " or "}?"
|
302
|
-
else
|
303
|
-
warn "Unknown answer, please try again!"
|
304
|
-
end
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
# display a question and show the default value
|
309
|
-
def self.prompt(question, default = nil)
|
310
|
-
msg = question.dup
|
311
|
-
|
312
|
-
case default
|
313
|
-
when true
|
314
|
-
msg << " [Yn]"
|
315
|
-
when false
|
316
|
-
msg << " [yN]"
|
317
|
-
else
|
318
|
-
msg << " [#{default.inspect}]" if default
|
319
|
-
end
|
320
|
-
|
321
|
-
display "#{msg}: ", false
|
322
|
-
end
|
323
|
-
|
324
|
-
# try to make `str' be the same class as `x'
|
325
|
-
def self.match_type(str, x)
|
326
|
-
case x
|
327
|
-
when Integer
|
328
|
-
str.to_i
|
329
|
-
when true, false
|
330
|
-
str.upcase.start_with? "Y"
|
331
|
-
else
|
332
|
-
str
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
# definitions for reading character-by-character
|
337
|
-
begin
|
338
|
-
require "Win32API"
|
339
|
-
|
340
|
-
def self.with_char_io(input)
|
341
|
-
yield
|
342
|
-
end
|
343
|
-
|
344
|
-
def self.get_character(input)
|
345
|
-
if input == STDIN
|
346
|
-
begin
|
347
|
-
Win32API.new("msvcrt", "_getch", [], "L").call.chr
|
348
|
-
rescue
|
349
|
-
Win32API.new("crtdll", "_getch", [], "L").call.chr
|
350
|
-
end
|
351
|
-
else
|
352
|
-
input.getc.chr
|
353
|
-
end
|
354
|
-
end
|
355
|
-
rescue LoadError
|
356
|
-
begin
|
357
|
-
require "termios"
|
358
|
-
|
359
|
-
def self.with_char_io(input)
|
360
|
-
return yield unless input.tty?
|
361
|
-
|
362
|
-
before = Termios.getattr(input)
|
363
|
-
|
364
|
-
new = before.dup
|
365
|
-
new.c_lflag &= ~(Termios::ECHO | Termios::ICANON)
|
366
|
-
new.c_cc[Termios::VMIN] = 1
|
367
|
-
|
368
|
-
begin
|
369
|
-
Termios.setattr(input, Termios::TCSANOW, new)
|
370
|
-
yield
|
371
|
-
ensure
|
372
|
-
Termios.setattr(input, Termios::TCSANOW, before)
|
373
|
-
end
|
374
|
-
end
|
375
|
-
|
376
|
-
def self.get_character(input)
|
377
|
-
input.getc.chr
|
378
|
-
end
|
379
|
-
rescue LoadError
|
380
|
-
# set tty modes for the duration of a block, restoring them afterward
|
381
|
-
def self.with_char_io(input)
|
382
|
-
return yield unless input.tty?
|
383
|
-
|
384
|
-
begin
|
385
|
-
before = `stty -g`
|
386
|
-
system("stty raw -echo -icanon isig")
|
387
|
-
yield
|
388
|
-
ensure
|
389
|
-
system("stty #{before}")
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
# this assumes we're wrapped in #with_stty
|
394
|
-
def self.get_character(input)
|
395
|
-
input.getc.chr
|
396
|
-
end
|
397
|
-
end
|
398
|
-
end
|
399
71
|
end
|
400
72
|
|
401
73
|
module VMCStringExtensions
|
data/lib/cli/runner.rb
CHANGED
@@ -438,6 +438,10 @@ class VMC::Cli::Runner
|
|
438
438
|
end
|
439
439
|
|
440
440
|
rescue OptionParser::InvalidOption => e
|
441
|
+
puts(e.message.red)
|
442
|
+
puts("\n")
|
443
|
+
puts(basic_usage)
|
444
|
+
@exit_status = false
|
441
445
|
rescue OptionParser::AmbiguousOption => e
|
442
446
|
puts(e.message.red)
|
443
447
|
puts("\n")
|
@@ -473,7 +477,7 @@ class VMC::Cli::Runner
|
|
473
477
|
rescue Interrupt => e
|
474
478
|
say("\nInterrupted".red)
|
475
479
|
@exit_status = false
|
476
|
-
rescue => e
|
480
|
+
rescue Exception => e
|
477
481
|
puts e.message.red
|
478
482
|
puts e.backtrace
|
479
483
|
@exit_status = false
|
data/lib/cli/version.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vmc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
version: 0.3.13
|
4
|
+
prerelease:
|
5
|
+
version: 0.3.13
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- VMware
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-11-02 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -61,38 +61,49 @@ dependencies:
|
|
61
61
|
type: :runtime
|
62
62
|
version_requirements: *id004
|
63
63
|
- !ruby/object:Gem::Dependency
|
64
|
-
name:
|
64
|
+
name: interact
|
65
65
|
prerelease: false
|
66
66
|
requirement: &id005 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ~>
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 0.2.0
|
72
|
+
type: :runtime
|
73
|
+
version_requirements: *id005
|
74
|
+
- !ruby/object:Gem::Dependency
|
75
|
+
name: rake
|
76
|
+
prerelease: false
|
77
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
67
78
|
none: false
|
68
79
|
requirements:
|
69
80
|
- - ">="
|
70
81
|
- !ruby/object:Gem::Version
|
71
82
|
version: "0"
|
72
83
|
type: :development
|
73
|
-
version_requirements: *
|
84
|
+
version_requirements: *id006
|
74
85
|
- !ruby/object:Gem::Dependency
|
75
86
|
name: rspec
|
76
87
|
prerelease: false
|
77
|
-
requirement: &
|
88
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
78
89
|
none: false
|
79
90
|
requirements:
|
80
91
|
- - ~>
|
81
92
|
- !ruby/object:Gem::Version
|
82
93
|
version: 1.3.0
|
83
94
|
type: :development
|
84
|
-
version_requirements: *
|
95
|
+
version_requirements: *id007
|
85
96
|
- !ruby/object:Gem::Dependency
|
86
97
|
name: webmock
|
87
98
|
prerelease: false
|
88
|
-
requirement: &
|
99
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
89
100
|
none: false
|
90
101
|
requirements:
|
91
102
|
- - "="
|
92
103
|
- !ruby/object:Gem::Version
|
93
104
|
version: 1.5.0
|
94
105
|
type: :development
|
95
|
-
version_requirements: *
|
106
|
+
version_requirements: *id008
|
96
107
|
description: Client library and CLI that provides access to the VMware Cloud Application Platform.
|
97
108
|
email: support@vmware.com
|
98
109
|
executables:
|
@@ -144,9 +155,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
144
155
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
156
|
none: false
|
146
157
|
requirements:
|
147
|
-
- - "
|
158
|
+
- - ">="
|
148
159
|
- !ruby/object:Gem::Version
|
149
|
-
version:
|
160
|
+
version: "0"
|
150
161
|
requirements: []
|
151
162
|
|
152
163
|
rubyforge_project:
|