vmc 0.3.15 → 0.3.16.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.
- data/config/clients.yml +7 -5
- data/lib/cli/commands/admin.rb +2 -2
- data/lib/cli/commands/apps.rb +414 -380
- data/lib/cli/commands/base.rb +162 -9
- data/lib/cli/commands/manifest.rb +56 -0
- data/lib/cli/commands/services.rb +5 -6
- data/lib/cli/commands/user.rb +1 -1
- data/lib/cli/config.rb +17 -9
- data/lib/cli/manifest_helper.rb +238 -0
- data/lib/cli/runner.rb +24 -10
- data/lib/cli/tunnel_helper.rb +36 -11
- data/lib/cli/version.rb +1 -1
- data/lib/cli.rb +2 -0
- data/lib/vmc/client.rb +29 -19
- data/lib/vmc/const.rb +7 -7
- metadata +29 -13
data/lib/cli/commands/base.rb
CHANGED
@@ -12,6 +12,8 @@ module VMC::Cli
|
|
12
12
|
|
13
13
|
attr_reader :no_prompt, :prompt_ok
|
14
14
|
|
15
|
+
MANIFEST = "manifest.yml"
|
16
|
+
|
15
17
|
def initialize(options={})
|
16
18
|
@options = options.dup
|
17
19
|
@no_prompt = @options[:noprompts]
|
@@ -21,6 +23,165 @@ module VMC::Cli
|
|
21
23
|
if WINDOWS
|
22
24
|
VMC::Cli::Config.colorize = false
|
23
25
|
end
|
26
|
+
|
27
|
+
@path = @options[:path] || '.'
|
28
|
+
|
29
|
+
load_manifest manifest_file if manifest_file
|
30
|
+
end
|
31
|
+
|
32
|
+
def manifest_file
|
33
|
+
return @options[:manifest] if @options[:manifest]
|
34
|
+
return @manifest_file if @manifest_file
|
35
|
+
|
36
|
+
where = File.expand_path(@path)
|
37
|
+
while true
|
38
|
+
if File.exists?(File.join(where, MANIFEST))
|
39
|
+
@manifest_file = File.join(where, MANIFEST)
|
40
|
+
break
|
41
|
+
elsif where == "/"
|
42
|
+
@manifest_file = nil
|
43
|
+
break
|
44
|
+
else
|
45
|
+
where = File.expand_path("../", where)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
@manifest_file
|
50
|
+
end
|
51
|
+
|
52
|
+
def load_manifest_structure(file)
|
53
|
+
manifest = YAML.load_file file
|
54
|
+
|
55
|
+
Array(manifest["inherit"]).each do |p|
|
56
|
+
manifest = merge_parent(manifest, p)
|
57
|
+
end
|
58
|
+
|
59
|
+
if apps = manifest["applications"]
|
60
|
+
apps.each do |k, v|
|
61
|
+
abs = File.expand_path(k, file)
|
62
|
+
if Dir.pwd.start_with? abs
|
63
|
+
manifest = merge_manifest(manifest, v)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
manifest
|
69
|
+
end
|
70
|
+
|
71
|
+
def resolve_manifest(manifest)
|
72
|
+
if apps = manifest["applications"]
|
73
|
+
apps.each_value do |v|
|
74
|
+
resolve_lexically(v, [manifest])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
resolve_lexically(manifest, [manifest])
|
79
|
+
end
|
80
|
+
|
81
|
+
def load_manifest(file)
|
82
|
+
@manifest = load_manifest_structure(file)
|
83
|
+
resolve_manifest(@manifest)
|
84
|
+
end
|
85
|
+
|
86
|
+
def merge_parent(child, path)
|
87
|
+
file = File.expand_path("../" + path, manifest_file)
|
88
|
+
merge_manifest(child, load_manifest_structure(file))
|
89
|
+
end
|
90
|
+
|
91
|
+
def merge_manifest(child, parent)
|
92
|
+
merge = proc do |_, old, new|
|
93
|
+
if new.is_a?(Hash) and old.is_a?(Hash)
|
94
|
+
old.merge(new, &merge)
|
95
|
+
else
|
96
|
+
new
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
parent.merge(child, &merge)
|
101
|
+
end
|
102
|
+
|
103
|
+
def resolve_lexically(val, ctx = [@manifest])
|
104
|
+
case val
|
105
|
+
when Hash
|
106
|
+
val.each_value do |v|
|
107
|
+
resolve_lexically(v, [val] + ctx)
|
108
|
+
end
|
109
|
+
when Array
|
110
|
+
val.each do |v|
|
111
|
+
resolve_lexically(v, ctx)
|
112
|
+
end
|
113
|
+
when String
|
114
|
+
val.gsub!(/\$\{([[:alnum:]\-]+)\}/) do
|
115
|
+
resolve_symbol($1, ctx)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
|
122
|
+
def resolve_symbol(sym, ctx)
|
123
|
+
case sym
|
124
|
+
when "target-base"
|
125
|
+
target_base(ctx)
|
126
|
+
|
127
|
+
when "target-url"
|
128
|
+
target_url(ctx)
|
129
|
+
|
130
|
+
when "random-word"
|
131
|
+
"%04x" % [rand(0x0100000)]
|
132
|
+
|
133
|
+
else
|
134
|
+
found = find_symbol(sym, ctx)
|
135
|
+
|
136
|
+
if found
|
137
|
+
resolve_lexically(found, ctx)
|
138
|
+
found
|
139
|
+
else
|
140
|
+
err(sym, "Unknown symbol in manifest: ")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def find_symbol(sym, ctx)
|
146
|
+
ctx.each do |h|
|
147
|
+
if val = resolve_in(h, sym)
|
148
|
+
return val
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
nil
|
153
|
+
end
|
154
|
+
|
155
|
+
def resolve_in(hash, *where)
|
156
|
+
find_in_hash(hash, ["properties"] + where) ||
|
157
|
+
find_in_hash(hash, ["applications", @application] + where) ||
|
158
|
+
find_in_hash(hash, where)
|
159
|
+
end
|
160
|
+
|
161
|
+
def manifest(*where)
|
162
|
+
resolve_in(@manifest, *where)
|
163
|
+
end
|
164
|
+
|
165
|
+
def find_in_hash(hash, where)
|
166
|
+
what = hash
|
167
|
+
where.each do |x|
|
168
|
+
return nil unless what.is_a?(Hash)
|
169
|
+
what = what[x]
|
170
|
+
end
|
171
|
+
|
172
|
+
what
|
173
|
+
end
|
174
|
+
|
175
|
+
def target_url(ctx = [])
|
176
|
+
find_symbol("target", ctx) || VMC::Cli::Config.target_url
|
177
|
+
end
|
178
|
+
|
179
|
+
def target_base(ctx = [])
|
180
|
+
if tgt = find_symbol("target", ctx)
|
181
|
+
VMC::Cli::Config.base_of(tgt)
|
182
|
+
else
|
183
|
+
VMC::Cli::Config.suggest_url
|
184
|
+
end
|
24
185
|
end
|
25
186
|
|
26
187
|
# Inject a client to help in testing.
|
@@ -37,16 +198,8 @@ module VMC::Cli
|
|
37
198
|
@client_info ||= client.info
|
38
199
|
end
|
39
200
|
|
40
|
-
def target_url
|
41
|
-
@target_url ||= VMC::Cli::Config.target_url
|
42
|
-
end
|
43
|
-
|
44
|
-
def target_base
|
45
|
-
@target_base ||= VMC::Cli::Config.suggest_url
|
46
|
-
end
|
47
|
-
|
48
201
|
def auth_token
|
49
|
-
@auth_token
|
202
|
+
@auth_token = VMC::Cli::Config.auth_token(@options[:token_file])
|
50
203
|
end
|
51
204
|
|
52
205
|
def runtimes_info
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module VMC::Cli::Command
|
2
|
+
class Manifest < Base
|
3
|
+
include VMC::Cli::ManifestHelper
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
super
|
7
|
+
|
8
|
+
# don't resolve any of the manifest template stuff
|
9
|
+
if manifest_file
|
10
|
+
@manifest = load_manifest_structure manifest_file
|
11
|
+
else
|
12
|
+
@manifest = {}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def edit
|
17
|
+
build_manifest
|
18
|
+
save_manifest
|
19
|
+
end
|
20
|
+
|
21
|
+
def extend(which)
|
22
|
+
parent = load_manifest_structure which
|
23
|
+
@manifest = load_manifest_structure which
|
24
|
+
|
25
|
+
build_manifest
|
26
|
+
|
27
|
+
simplify(@manifest, parent)
|
28
|
+
|
29
|
+
@manifest["inherit"] ||= []
|
30
|
+
@manifest["inherit"] << which
|
31
|
+
|
32
|
+
save_manifest(ask("Save where?"))
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def simplify(child, parent)
|
38
|
+
return unless child.is_a?(Hash) and parent.is_a?(Hash)
|
39
|
+
|
40
|
+
child.reject! do |k, v|
|
41
|
+
if v == parent[k]
|
42
|
+
puts "rejecting #{k}"
|
43
|
+
true
|
44
|
+
else
|
45
|
+
simplify(v, parent[k])
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_manifest
|
52
|
+
@application = ask("Configure for which application?", :default => ".")
|
53
|
+
interact true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "uuidtools"
|
2
|
+
|
1
3
|
module VMC::Cli::Command
|
2
4
|
|
3
5
|
class Services < Base
|
@@ -112,21 +114,18 @@ module VMC::Cli::Command
|
|
112
114
|
|
113
115
|
err "Unknown service '#{service}'" unless info
|
114
116
|
|
115
|
-
# TODO: rather than default to a particular port, we should get
|
116
|
-
# the defaults based on the service name.. i.e. known services should
|
117
|
-
# have known local default ports for this side of the tunnel.
|
118
117
|
port = pick_tunnel_port(@options[:port] || 10000)
|
119
118
|
|
120
119
|
raise VMC::Client::AuthError unless client.logged_in?
|
121
120
|
|
122
121
|
if not tunnel_pushed?
|
123
122
|
display "Deploying tunnel application '#{tunnel_appname}'."
|
124
|
-
auth =
|
123
|
+
auth = UUIDTools::UUID.random_create.to_s
|
125
124
|
push_caldecott(auth)
|
126
125
|
bind_service_banner(service, tunnel_appname, false)
|
127
126
|
start_caldecott
|
128
127
|
else
|
129
|
-
auth =
|
128
|
+
auth = tunnel_auth
|
130
129
|
end
|
131
130
|
|
132
131
|
if not tunnel_healthy?(auth)
|
@@ -166,7 +165,7 @@ module VMC::Cli::Command
|
|
166
165
|
wait_for_tunnel_end
|
167
166
|
else
|
168
167
|
wait_for_tunnel_start(port)
|
169
|
-
unless start_local_prog(clients
|
168
|
+
unless start_local_prog(clients, client_name, conn_info, port)
|
170
169
|
err "'#{client_name}' executation failed; is it in your $PATH?"
|
171
170
|
end
|
172
171
|
end
|
data/lib/cli/commands/user.rb
CHANGED
data/lib/cli/config.rb
CHANGED
@@ -37,6 +37,10 @@ module VMC::Cli
|
|
37
37
|
@target_url
|
38
38
|
end
|
39
39
|
|
40
|
+
def base_of(url)
|
41
|
+
url.sub(/^[^\.]+\./, "")
|
42
|
+
end
|
43
|
+
|
40
44
|
def suggest_url
|
41
45
|
return @suggest_url if @suggest_url
|
42
46
|
ha = target_url.split('.')
|
@@ -51,8 +55,8 @@ module VMC::Cli
|
|
51
55
|
lock_and_write(target_file, target_host)
|
52
56
|
end
|
53
57
|
|
54
|
-
def all_tokens
|
55
|
-
token_file = File.expand_path(TOKEN_FILE)
|
58
|
+
def all_tokens(token_file_path=nil)
|
59
|
+
token_file = File.expand_path(token_file_path || TOKEN_FILE)
|
56
60
|
return nil unless File.exists? token_file
|
57
61
|
contents = lock_and_read(token_file).strip
|
58
62
|
JSON.parse(contents)
|
@@ -60,9 +64,9 @@ module VMC::Cli
|
|
60
64
|
|
61
65
|
alias :targets :all_tokens
|
62
66
|
|
63
|
-
def auth_token
|
67
|
+
def auth_token(token_file_path=nil)
|
64
68
|
return @token if @token
|
65
|
-
tokens = all_tokens
|
69
|
+
tokens = all_tokens(token_file_path)
|
66
70
|
@token = tokens[target_url] if tokens
|
67
71
|
end
|
68
72
|
|
@@ -70,10 +74,10 @@ module VMC::Cli
|
|
70
74
|
FileUtils.rm_f(File.expand_path(TOKEN_FILE))
|
71
75
|
end
|
72
76
|
|
73
|
-
def store_token(token)
|
74
|
-
tokens = all_tokens || {}
|
77
|
+
def store_token(token, token_file_path=nil)
|
78
|
+
tokens = all_tokens(token_file_path) || {}
|
75
79
|
tokens[target_url] = token
|
76
|
-
token_file = File.expand_path(TOKEN_FILE)
|
80
|
+
token_file = File.expand_path(token_file_path || TOKEN_FILE)
|
77
81
|
lock_and_write(token_file, tokens.to_json)
|
78
82
|
end
|
79
83
|
|
@@ -129,8 +133,12 @@ module VMC::Cli
|
|
129
133
|
end
|
130
134
|
|
131
135
|
def lock_and_read(file)
|
132
|
-
File.open(file,
|
133
|
-
|
136
|
+
File.open(file, File::RDONLY) {|f|
|
137
|
+
if defined? JRUBY_VERSION
|
138
|
+
f.flock(File::LOCK_SH)
|
139
|
+
else
|
140
|
+
f.flock(File::LOCK_EX)
|
141
|
+
end
|
134
142
|
contents = f.read
|
135
143
|
f.flock(File::LOCK_UN)
|
136
144
|
contents
|
@@ -0,0 +1,238 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
module VMC::Cli::ManifestHelper
|
4
|
+
include VMC::Cli::ServicesHelper
|
5
|
+
|
6
|
+
DEFAULTS = {
|
7
|
+
"url" => "${name}.${target-base}",
|
8
|
+
"mem" => "128M",
|
9
|
+
"instances" => 1
|
10
|
+
}
|
11
|
+
|
12
|
+
MANIFEST = "manifest.yml"
|
13
|
+
|
14
|
+
YES_SET = Set.new(["y", "Y", "yes", "YES"])
|
15
|
+
|
16
|
+
# take a block and call it once for each app to push/update.
|
17
|
+
# with @application and @app_info set appropriately
|
18
|
+
def each_app(panic=true)
|
19
|
+
if @manifest and all_apps = @manifest["applications"]
|
20
|
+
where = File.expand_path(@path)
|
21
|
+
single = false
|
22
|
+
|
23
|
+
all_apps.each do |path, info|
|
24
|
+
app = File.expand_path("../" + path, manifest_file)
|
25
|
+
if where.start_with?(app)
|
26
|
+
@application = app
|
27
|
+
@app_info = info
|
28
|
+
yield info["name"]
|
29
|
+
single = true
|
30
|
+
break
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
unless single
|
35
|
+
if where == File.expand_path("../", manifest_file)
|
36
|
+
ordered_by_deps(all_apps).each do |path, info|
|
37
|
+
app = File.expand_path("../" + path, manifest_file)
|
38
|
+
@application = app
|
39
|
+
@app_info = info
|
40
|
+
yield info["name"]
|
41
|
+
end
|
42
|
+
else
|
43
|
+
err "Path '#{@path}' is not known to manifest '#{manifest_file}'."
|
44
|
+
end
|
45
|
+
end
|
46
|
+
else
|
47
|
+
@application = @path
|
48
|
+
@app_info = @manifest
|
49
|
+
if @app_info
|
50
|
+
yield @app_info["name"]
|
51
|
+
elsif panic
|
52
|
+
err "No applications."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
nil
|
57
|
+
ensure
|
58
|
+
@application = nil
|
59
|
+
@app_info = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def interact(many=false)
|
63
|
+
@manifest ||= {}
|
64
|
+
configure_app(many)
|
65
|
+
end
|
66
|
+
|
67
|
+
def target_manifest
|
68
|
+
@options[:manifest] || MANIFEST
|
69
|
+
end
|
70
|
+
|
71
|
+
def save_manifest(save_to = nil)
|
72
|
+
save_to ||= target_manifest
|
73
|
+
|
74
|
+
File.open(save_to, "w") do |f|
|
75
|
+
f.write @manifest.to_yaml
|
76
|
+
end
|
77
|
+
|
78
|
+
say "Manifest written to #{save_to}."
|
79
|
+
end
|
80
|
+
|
81
|
+
def configure_app(many=false)
|
82
|
+
name = manifest("name") ||
|
83
|
+
set(ask("Application Name", :default => manifest("name")), "name")
|
84
|
+
|
85
|
+
url_template = manifest("url") || DEFAULTS["url"]
|
86
|
+
url_resolved = url_template.dup
|
87
|
+
resolve_lexically(url_resolved)
|
88
|
+
|
89
|
+
url = ask("Application Deployed URL", :default => url_resolved)
|
90
|
+
|
91
|
+
url = url_template if url == url_resolved
|
92
|
+
|
93
|
+
# common error case is for prompted users to answer y or Y or yes or
|
94
|
+
# YES to this ask() resulting in an unintended URL of y. Special
|
95
|
+
# case this common error
|
96
|
+
url = DEFAULTS["url"] if YES_SET.member? url
|
97
|
+
|
98
|
+
set url, "url"
|
99
|
+
|
100
|
+
unless manifest "framework"
|
101
|
+
framework = detect_framework
|
102
|
+
set framework.name, "framework", "name"
|
103
|
+
set(
|
104
|
+
{ "mem" => framework.mem,
|
105
|
+
"description" => framework.description,
|
106
|
+
"exec" => framework.exec
|
107
|
+
},
|
108
|
+
"framework",
|
109
|
+
"info"
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
set ask(
|
114
|
+
"Memory reservation",
|
115
|
+
:default =>
|
116
|
+
manifest("mem") ||
|
117
|
+
manifest("framework", "info", "mem") ||
|
118
|
+
DEFAULTS["mem"],
|
119
|
+
:choices => ["128M", "256M", "512M", "1G", "2G"]
|
120
|
+
), "mem"
|
121
|
+
|
122
|
+
set ask(
|
123
|
+
"How many instances?",
|
124
|
+
:default => manifest("instances") || DEFAULTS["instances"]
|
125
|
+
), "instances"
|
126
|
+
|
127
|
+
unless manifest "services"
|
128
|
+
services = client.services_info
|
129
|
+
unless services.empty?
|
130
|
+
bind = ask "Would you like to bind any services to '#{name}'?", :default => false
|
131
|
+
bind_services(services.values.collect(&:keys).flatten) if bind
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
if many and ask("Configure for another application?", :default => false)
|
136
|
+
@application = ask "Application path?"
|
137
|
+
configure_app
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def set(what, *where)
|
142
|
+
where.unshift "applications", @application
|
143
|
+
|
144
|
+
which = @manifest
|
145
|
+
where.each_with_index do |k, i|
|
146
|
+
if i + 1 == where.size
|
147
|
+
which[k] = what
|
148
|
+
else
|
149
|
+
which = (which[k] ||= {})
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
what
|
154
|
+
end
|
155
|
+
|
156
|
+
# Detect the appropriate framework.
|
157
|
+
def detect_framework(prompt_ok = true)
|
158
|
+
framework = VMC::Cli::Framework.detect(@application)
|
159
|
+
framework_correct = ask("Detected a #{framework}, is this correct?", :default => true) if prompt_ok && framework
|
160
|
+
if prompt_ok && (framework.nil? || !framework_correct)
|
161
|
+
display "#{"[WARNING]".yellow} Can't determine the Application Type." unless framework
|
162
|
+
framework = nil if !framework_correct
|
163
|
+
framework = VMC::Cli::Framework.lookup(
|
164
|
+
ask(
|
165
|
+
"Select Application Type",
|
166
|
+
:indexed => true,
|
167
|
+
:default => framework,
|
168
|
+
:choices => VMC::Cli::Framework.known_frameworks
|
169
|
+
)
|
170
|
+
)
|
171
|
+
display "Selected #{framework}"
|
172
|
+
end
|
173
|
+
|
174
|
+
framework
|
175
|
+
end
|
176
|
+
|
177
|
+
def bind_services(services)
|
178
|
+
svcs = services.collect(&:to_s).sort!
|
179
|
+
|
180
|
+
display "The following system services are available"
|
181
|
+
configure_service(
|
182
|
+
ask(
|
183
|
+
"Please select the one you wish to provision",
|
184
|
+
:indexed => true,
|
185
|
+
:choices => svcs
|
186
|
+
).to_sym
|
187
|
+
)
|
188
|
+
|
189
|
+
if ask "Would you like to bind another service?", :default => false
|
190
|
+
bind_services(services)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def configure_service(vendor)
|
195
|
+
default_name = random_service_name(vendor)
|
196
|
+
name = ask "Specify the name of the service", :default => default_name
|
197
|
+
|
198
|
+
set vendor, "services", name, "type"
|
199
|
+
end
|
200
|
+
|
201
|
+
private
|
202
|
+
def ordered_by_deps(apps, abspaths = nil, processed = Set[])
|
203
|
+
unless abspaths
|
204
|
+
abspaths = {}
|
205
|
+
apps.each do |p, i|
|
206
|
+
ep = File.expand_path("../" + p, manifest_file)
|
207
|
+
abspaths[ep] = i
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
ordered = []
|
212
|
+
apps.each do |path, info|
|
213
|
+
epath = File.expand_path("../" + path, manifest_file)
|
214
|
+
|
215
|
+
if deps = info["depends-on"]
|
216
|
+
dep_apps = {}
|
217
|
+
deps.each do |dep|
|
218
|
+
edep = File.expand_path("../" + dep, manifest_file)
|
219
|
+
|
220
|
+
err "Circular dependency detected." if processed.include? edep
|
221
|
+
|
222
|
+
dep_apps[dep] = abspaths[edep]
|
223
|
+
end
|
224
|
+
|
225
|
+
processed.add(epath)
|
226
|
+
|
227
|
+
ordered += ordered_by_deps(dep_apps, abspaths, processed)
|
228
|
+
ordered << [path, info]
|
229
|
+
elsif not processed.include? epath
|
230
|
+
ordered << [path, info]
|
231
|
+
processed.add(epath)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
ordered
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
data/lib/cli/runner.rb
CHANGED
@@ -31,6 +31,7 @@ class VMC::Cli::Runner
|
|
31
31
|
opts.on('--passwd PASS') { |pass| @options[:password] = pass }
|
32
32
|
opts.on('--pass PASS') { |pass| @options[:password] = pass }
|
33
33
|
opts.on('--password PASS') { |pass| @options[:password] = pass }
|
34
|
+
opts.on('--token-file TOKEN_FILE') { |token_file| @options[:token_file] = token_file }
|
34
35
|
opts.on('--app NAME') { |name| @options[:name] = name }
|
35
36
|
opts.on('--name NAME') { |name| @options[:name] = name }
|
36
37
|
opts.on('--bind BIND') { |bind| @options[:bind] = bind }
|
@@ -52,6 +53,10 @@ class VMC::Cli::Runner
|
|
52
53
|
opts.on('-d [MODE]') { |mode| @options[:debug] = mode || "run" }
|
53
54
|
opts.on('--debug [MODE]') { |mode| @options[:debug] = mode || "run" }
|
54
55
|
|
56
|
+
# override manifest file
|
57
|
+
opts.on('-m FILE') { |file| @options[:manifest] = file }
|
58
|
+
opts.on('--manifest FILE') { |file| @options[:manifest] = file }
|
59
|
+
|
55
60
|
opts.on('-q', '--quiet') { @options[:quiet] = true }
|
56
61
|
|
57
62
|
# Don't use builtin zip
|
@@ -223,15 +228,15 @@ class VMC::Cli::Runner
|
|
223
228
|
|
224
229
|
when 'start'
|
225
230
|
usage('vmc start <appname>')
|
226
|
-
set_cmd(:apps, :start, 1)
|
231
|
+
set_cmd(:apps, :start, @args.size == 1 ? 1 : 0)
|
227
232
|
|
228
233
|
when 'stop'
|
229
234
|
usage('vmc stop <appname>')
|
230
|
-
set_cmd(:apps, :stop, 1)
|
235
|
+
set_cmd(:apps, :stop, @args.size == 1 ? 1 : 0)
|
231
236
|
|
232
237
|
when 'restart'
|
233
238
|
usage('vmc restart <appname>')
|
234
|
-
set_cmd(:apps, :restart, 1)
|
239
|
+
set_cmd(:apps, :restart, @args.size == 1 ? 1 : 0)
|
235
240
|
|
236
241
|
when 'rename'
|
237
242
|
usage('vmc rename <appname> <newname>')
|
@@ -247,7 +252,7 @@ class VMC::Cli::Runner
|
|
247
252
|
|
248
253
|
when 'stats'
|
249
254
|
usage('vmc stats <appname>')
|
250
|
-
set_cmd(:apps, :stats, 1)
|
255
|
+
set_cmd(:apps, :stats, @args.size == 1 ? 1 : 0)
|
251
256
|
|
252
257
|
when 'map'
|
253
258
|
usage('vmc map <appname> <url>')
|
@@ -278,12 +283,12 @@ class VMC::Cli::Runner
|
|
278
283
|
set_cmd(:apps, :logs, 1)
|
279
284
|
|
280
285
|
when 'instances', 'scale'
|
281
|
-
if @args.size
|
282
|
-
usage('vmc instances <appname>')
|
283
|
-
set_cmd(:apps, :instances, 1)
|
284
|
-
else
|
286
|
+
if @args.size > 1
|
285
287
|
usage('vmc instances <appname> <num|delta>')
|
286
288
|
set_cmd(:apps, :instances, 2)
|
289
|
+
else
|
290
|
+
usage('vmc instances <appname>')
|
291
|
+
set_cmd(:apps, :instances, @args.size == 1 ? 1 : 0)
|
287
292
|
end
|
288
293
|
|
289
294
|
when 'crashes'
|
@@ -304,7 +309,7 @@ class VMC::Cli::Runner
|
|
304
309
|
|
305
310
|
when 'update'
|
306
311
|
usage('vmc update <appname> [--path PATH]')
|
307
|
-
set_cmd(:apps, :update, 1)
|
312
|
+
set_cmd(:apps, :update, @args.size == 1 ? 1 : 0)
|
308
313
|
|
309
314
|
when 'services'
|
310
315
|
usage('vmc services')
|
@@ -389,6 +394,14 @@ class VMC::Cli::Runner
|
|
389
394
|
@args = @args.unshift('--options')
|
390
395
|
parse_options!
|
391
396
|
|
397
|
+
when 'manifest'
|
398
|
+
usage('vmc manifest')
|
399
|
+
set_cmd(:manifest, :edit)
|
400
|
+
|
401
|
+
when 'extend-manifest'
|
402
|
+
usage('vmc extend-manifest')
|
403
|
+
set_cmd(:manifest, :extend, 1)
|
404
|
+
|
392
405
|
else
|
393
406
|
if verb
|
394
407
|
display "vmc: Unknown command [#{verb}]"
|
@@ -437,7 +450,8 @@ class VMC::Cli::Runner
|
|
437
450
|
parse_command!
|
438
451
|
|
439
452
|
if @namespace && @action
|
440
|
-
|
453
|
+
cmd = VMC::Cli::Command.const_get(@namespace.to_s.capitalize)
|
454
|
+
cmd.new(@options).send(@action, *@args.collect(&:dup))
|
441
455
|
elsif @help_only || @usage
|
442
456
|
display_usage
|
443
457
|
else
|