vmc 0.4.0.beta.93 → 0.4.0.beta.94

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 (65) hide show
  1. data/vmc-ng/Rakefile +21 -30
  2. data/vmc-ng/lib/vmc.rb +4 -3
  3. data/vmc-ng/lib/vmc/cli.rb +10 -9
  4. data/vmc-ng/lib/vmc/cli/app/app.rb +45 -0
  5. data/vmc-ng/lib/vmc/cli/app/apps.rb +97 -0
  6. data/vmc-ng/lib/vmc/cli/app/base.rb +82 -0
  7. data/vmc-ng/lib/vmc/cli/app/crashes.rb +41 -0
  8. data/vmc-ng/lib/vmc/cli/app/delete.rb +90 -0
  9. data/vmc-ng/lib/vmc/cli/app/deprecated.rb +11 -0
  10. data/vmc-ng/lib/vmc/cli/app/env.rb +86 -0
  11. data/vmc-ng/lib/vmc/cli/app/files.rb +85 -0
  12. data/vmc-ng/lib/vmc/cli/app/health.rb +27 -0
  13. data/vmc-ng/lib/vmc/cli/app/instances.rb +49 -0
  14. data/vmc-ng/lib/vmc/cli/app/logs.rb +80 -0
  15. data/vmc-ng/lib/vmc/cli/app/push.rb +336 -0
  16. data/vmc-ng/lib/vmc/cli/app/rename.rb +31 -0
  17. data/vmc-ng/lib/vmc/cli/app/restart.rb +23 -0
  18. data/vmc-ng/lib/vmc/cli/app/routes.rb +97 -0
  19. data/vmc-ng/lib/vmc/cli/app/scale.rb +67 -0
  20. data/vmc-ng/lib/vmc/cli/app/start.rb +96 -0
  21. data/vmc-ng/lib/vmc/cli/app/stats.rb +68 -0
  22. data/vmc-ng/lib/vmc/cli/app/stop.rb +29 -0
  23. data/vmc-ng/lib/vmc/cli/domain/add_domain.rb +27 -0
  24. data/vmc-ng/lib/vmc/cli/domain/base.rb +12 -0
  25. data/vmc-ng/lib/vmc/cli/domain/create_domain.rb +31 -0
  26. data/vmc-ng/lib/vmc/cli/domain/delete_domain.rb +51 -0
  27. data/vmc-ng/lib/vmc/cli/domain/domains.rb +43 -0
  28. data/vmc-ng/lib/vmc/cli/domain/remove_domain.rb +26 -0
  29. data/vmc-ng/lib/vmc/cli/help.rb +0 -1
  30. data/vmc-ng/lib/vmc/cli/interactive.rb +4 -0
  31. data/vmc-ng/lib/vmc/cli/route/base.rb +12 -0
  32. data/vmc-ng/lib/vmc/cli/route/create_route.rb +42 -0
  33. data/vmc-ng/lib/vmc/cli/route/delete_route.rb +42 -0
  34. data/vmc-ng/lib/vmc/cli/route/routes.rb +26 -0
  35. data/vmc-ng/lib/vmc/detect.rb +2 -2
  36. data/vmc-ng/lib/vmc/spec_helper.rb +1 -0
  37. data/vmc-ng/lib/vmc/version.rb +1 -1
  38. data/vmc-ng/spec/cli/app/push_spec.rb +34 -0
  39. data/vmc-ng/spec/cli/app/rename_spec.rb +108 -0
  40. data/vmc-ng/spec/cli/route/delete_route_spec.rb +160 -0
  41. data/vmc-ng/spec/detect_spec.rb +54 -0
  42. data/vmc-ng/spec/factories/app_factory.rb +9 -0
  43. data/vmc-ng/spec/factories/client_factory.rb +16 -0
  44. data/vmc-ng/spec/factories/domain_factory.rb +9 -0
  45. data/vmc-ng/spec/factories/factory.rb +3 -0
  46. data/vmc-ng/spec/factories/framework_factory.rb +9 -0
  47. data/vmc-ng/spec/factories/route_factory.rb +10 -0
  48. data/vmc-ng/spec/spec_helper.rb +17 -0
  49. data/vmc-ng/spec/support/interact_helpers.rb +23 -0
  50. metadata +135 -62
  51. data/vmc-ng/lib/vmc/cli/app.rb +0 -1333
  52. data/vmc-ng/lib/vmc/cli/domain.rb +0 -164
  53. data/vmc-ng/lib/vmc/cli/route.rb +0 -106
  54. data/vmc-ng/lib/vmc/spec_helpers.rb +0 -431
  55. data/vmc-ng/lib/vmc/spec_helpers/eventlog.rb +0 -277
  56. data/vmc-ng/lib/vmc/spec_helpers/patches.rb +0 -94
  57. data/vmc-ng/spec/Rakefile +0 -13
  58. data/vmc-ng/spec/app/app_spec.rb +0 -19
  59. data/vmc-ng/spec/app/apps_spec.rb +0 -79
  60. data/vmc-ng/spec/app/push_spec.rb +0 -74
  61. data/vmc-ng/spec/assets/hello-sinatra/Gemfile +0 -2
  62. data/vmc-ng/spec/assets/hello-sinatra/main.rb +0 -5
  63. data/vmc-ng/spec/assets/hello-sinatra/manifest.yml +0 -9
  64. data/vmc-ng/spec/helpers.rb +0 -7
  65. data/vmc-ng/spec/start/target_spec.rb +0 -60
@@ -0,0 +1,11 @@
1
+ require "vmc/cli/app/base"
2
+
3
+ module VMC::App
4
+ class Deprecated < Base
5
+ desc "DEPRECATED. Use 'push' instead."
6
+ input :app, :argument => :optional
7
+ def update
8
+ fail "The 'update' command is no longer needed; use 'push' instead."
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,86 @@
1
+ require "vmc/cli/app/base"
2
+
3
+ module VMC::App
4
+ class Env < Base
5
+ VALID_ENV_VAR = /^[a-zA-Za-z_][[:alnum:]_]*$/
6
+
7
+ desc "Show all environment variables set for an app"
8
+ group :apps, :info, :hidden => true
9
+ input :app, :argument => true,
10
+ :desc => "Application to inspect the environment of",
11
+ :from_given => by_name("app")
12
+ def env
13
+ app = input[:app]
14
+
15
+ vars =
16
+ with_progress("Getting env for #{c(app.name, :name)}") do |s|
17
+ app.env
18
+ end
19
+
20
+ line unless quiet?
21
+
22
+ vars.each do |name, val|
23
+ line "#{c(name, :name)}: #{val}"
24
+ end
25
+ end
26
+
27
+ desc "Set an environment variable"
28
+ group :apps, :info, :hidden => true
29
+ input :app, :argument => true,
30
+ :desc => "Application to set the variable for",
31
+ :from_given => by_name("app")
32
+ input :name, :argument => true,
33
+ :desc => "Environment variable name"
34
+ input :value, :argument => :optional,
35
+ :desc => "Environment variable value"
36
+ input :restart, :type => :boolean, :default => true,
37
+ :desc => "Restart app after updating?"
38
+ def set_env
39
+ app = input[:app]
40
+ name = input[:name]
41
+
42
+ if value = input[:value]
43
+ name = input[:name]
44
+ elsif name["="]
45
+ name, value = name.split("=")
46
+ end
47
+
48
+ unless name =~ VALID_ENV_VAR
49
+ fail "Invalid variable name; must match #{VALID_ENV_VAR.inspect}"
50
+ end
51
+
52
+ with_progress("Updating #{c(app.name, :name)}") do
53
+ app.env[name] = value
54
+ app.update!
55
+ end
56
+
57
+ if app.started? && input[:restart]
58
+ invoke :restart, :app => app
59
+ end
60
+ end
61
+
62
+
63
+ desc "Remove an environment variable"
64
+ group :apps, :info, :hidden => true
65
+ input :app, :argument => true,
66
+ :desc => "Application to set the variable for",
67
+ :from_given => by_name("app")
68
+ input :name, :argument => true,
69
+ :desc => "Environment variable name"
70
+ input :restart, :type => :boolean, :default => true,
71
+ :desc => "Restart app after updating?"
72
+ def unset_env
73
+ app = input[:app]
74
+ name = input[:name]
75
+
76
+ with_progress("Updating #{c(app.name, :name)}") do
77
+ app.env.delete(name)
78
+ app.update!
79
+ end
80
+
81
+ if app.started? && input[:restart]
82
+ invoke :restart, :app => app
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,85 @@
1
+ require "vmc/cli/app/base"
2
+
3
+ module VMC::App
4
+ class Files < Base
5
+ desc "Print out an app's file contents"
6
+ group :apps, :info, :hidden => true
7
+ input :app, :argument => true,
8
+ :desc => "Application to inspect the files of",
9
+ :from_given => by_name("app")
10
+ input :path, :argument => true, :default => "/",
11
+ :desc => "Path of file to read"
12
+ def file
13
+ app = input[:app]
14
+ path = input[:path]
15
+
16
+ file =
17
+ with_progress("Getting file contents") do
18
+ app.file(*path.split("/"))
19
+ end
20
+
21
+ if quiet?
22
+ print file
23
+ else
24
+ line
25
+
26
+ file.split("\n").each do |l|
27
+ line l
28
+ end
29
+ end
30
+ rescue CFoundry::NotFound
31
+ fail "Invalid path #{b(path)} for app #{b(app.name)}"
32
+ rescue CFoundry::FileError => e
33
+ fail e.description
34
+ end
35
+
36
+ desc "Examine an app's files"
37
+ group :apps, :info, :hidden => true
38
+ input :app, :argument => true,
39
+ :desc => "Application to inspect the files of",
40
+ :from_given => by_name("app")
41
+ input :path, :argument => :optional, :default => "/",
42
+ :desc => "Path of directory to list"
43
+ def files
44
+ app = input[:app]
45
+ path = input[:path]
46
+
47
+ if quiet?
48
+ files =
49
+ with_progress("Getting file listing") do
50
+ app.files(*path.split("/"))
51
+ end
52
+
53
+ files.each do |file|
54
+ line file.join("/")
55
+ end
56
+ else
57
+ invoke :file, :app => app, :path => path
58
+ end
59
+ rescue CFoundry::NotFound
60
+ fail "Invalid path #{b(path)} for app #{b(app.name)}"
61
+ rescue CFoundry::FileError => e
62
+ fail e.description
63
+ end
64
+
65
+ desc "Stream an app's file contents"
66
+ group :apps, :info, :hidden => true
67
+ input :app, :argument => true,
68
+ :desc => "Application to inspect the file of",
69
+ :from_given => by_name("app")
70
+ input :path, :argument => true, :default => "/",
71
+ :desc => "Path of file to stream"
72
+ def tail
73
+ app = input[:app]
74
+ path = input[:path]
75
+
76
+ app.stream_file(*path.split("/")) do |contents|
77
+ print contents
78
+ end
79
+ rescue CFoundry::NotFound
80
+ fail "Invalid path #{b(path)} for app #{b(app.name)}"
81
+ rescue CFoundry::FileError => e
82
+ fail e.description
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,27 @@
1
+ require "vmc/cli/app/base"
2
+
3
+ module VMC::App
4
+ class Health < Base
5
+ desc "Get application health"
6
+ group :apps, :info, :hidden => true
7
+ input :apps, :argument => :splat, :singular => :app,
8
+ :desc => "Applications to start",
9
+ :from_given => by_name("app")
10
+ def health
11
+ apps = input[:apps]
12
+ fail "No applications given." if apps.empty?
13
+
14
+ health =
15
+ with_progress("Getting health status") do
16
+ apps.collect { |a| [a, app_status(a)] }
17
+ end
18
+
19
+ line unless quiet?
20
+
21
+ spaced(health) do |app, status|
22
+ start_line "#{c(app.name, :name)}: " unless quiet?
23
+ puts status
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,49 @@
1
+ require "vmc/cli/app/base"
2
+
3
+ module VMC::App
4
+ class Instances < Base
5
+ desc "List an app's instances"
6
+ group :apps, :info, :hidden => true
7
+ input :apps, :argument => :splat, :singular => :app,
8
+ :desc => "Applications whose instances to list",
9
+ :from_given => by_name("app")
10
+ def instances
11
+ apps = input[:apps]
12
+ fail "No applications given." if apps.empty?
13
+
14
+ spaced(apps) do |app|
15
+ instances =
16
+ with_progress("Getting instances for #{c(app.name, :name)}") do
17
+ app.instances
18
+ end
19
+
20
+ spaced(instances) do |i|
21
+ if quiet?
22
+ line i.id
23
+ else
24
+ display_instance(i)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def display_instance(i)
31
+ start_line "instance #{c("\##{i.id}", :instance)}: "
32
+ puts "#{b(c(i.state.downcase, state_color(i.state)))} "
33
+
34
+ indented do
35
+ if s = i.since
36
+ line "started: #{c(s.strftime("%F %r"), :neutral)}"
37
+ end
38
+
39
+ if d = i.debugger
40
+ line "debugger: port #{b(d[:port])} at #{b(d[:ip])}"
41
+ end
42
+
43
+ if c = i.console
44
+ line "console: port #{b(c[:port])} at #{b(c[:ip])}"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,80 @@
1
+ require "vmc/cli/app/base"
2
+
3
+ module VMC::App
4
+ class Logs < Base
5
+ desc "Print out an app's logs"
6
+ group :apps, :info, :hidden => true
7
+ input :app, :argument => true,
8
+ :desc => "Application to get the logs of",
9
+ :from_given => by_name("app")
10
+ input :instance, :default => "0",
11
+ :desc => "Instance of application to get the logs of"
12
+ input :all, :type => :boolean, :default => false,
13
+ :desc => "Get logs for every instance"
14
+ def logs
15
+ app = input[:app]
16
+
17
+ instances =
18
+ if input[:all] || input[:instance] == "all"
19
+ app.instances
20
+ else
21
+ app.instances.select { |i| i.id == input[:instance] }
22
+ end
23
+
24
+ if instances.empty?
25
+ if input[:all]
26
+ fail "No instances found."
27
+ else
28
+ fail "Instance #{app.name} \##{input[:instance]} not found."
29
+ end
30
+ end
31
+
32
+ spaced(instances) do |i|
33
+ show_instance_logs(app, i)
34
+ end
35
+ end
36
+
37
+ desc "Print out the logs for an app's crashed instances"
38
+ group :apps, :info, :hidden => true
39
+ input :app, :argument => true,
40
+ :desc => "Application to get the logs of",
41
+ :from_given => by_name("app")
42
+ def crashlogs
43
+ app = input[:app]
44
+
45
+ crashes = app.crashes
46
+
47
+ fail "No crashed instances found." if crashes.empty?
48
+
49
+ spaced(crashes) do |i|
50
+ show_instance_logs(app, i)
51
+ end
52
+ end
53
+
54
+ def show_instance_logs(app, i)
55
+ return unless i.id
56
+
57
+ logs =
58
+ with_progress(
59
+ "Getting logs for #{c(app.name, :name)} " +
60
+ c("\##{i.id}", :instance)) do
61
+ i.files("logs")
62
+ end
63
+
64
+ line unless quiet?
65
+
66
+ spaced(logs) do |log|
67
+ begin
68
+ body =
69
+ with_progress("Reading " + b(log.join("/"))) do |s|
70
+ i.file(*log)
71
+ end
72
+
73
+ lines body
74
+ line unless body.empty?
75
+ rescue CFoundry::NotFound
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,336 @@
1
+ require "vmc/detect"
2
+
3
+ require "vmc/cli/app/base"
4
+
5
+ module VMC::App
6
+ class Push < Base
7
+ desc "Push an application, syncing changes if it exists"
8
+ group :apps, :manage
9
+ input(:name, :argument => true, :desc => "Application name") {
10
+ ask("Name")
11
+ }
12
+ input :path, :default => ".",
13
+ :desc => "Path containing the application"
14
+ input(:url, :desc => "URL bound to app") { |name|
15
+ choices = url_choices(name)
16
+
17
+ options = {
18
+ :choices => choices + ["none"],
19
+ :allow_other => true
20
+ }
21
+
22
+ options[:default] = choices.first if choices.size == 1
23
+
24
+ url = ask "URL", options
25
+
26
+ unless url == "none"
27
+ url
28
+ end
29
+ }
30
+ input(:memory, :desc => "Memory limit") { |default|
31
+ ask("Memory Limit",
32
+ :choices => memory_choices,
33
+ :allow_other => true,
34
+ :default => default || "64M")
35
+ }
36
+ input(:instances, :type => :integer,
37
+ :desc => "Number of instances to run") {
38
+ ask("Instances", :default => 1)
39
+ }
40
+ input(:framework, :from_given => find_by_name("framework"),
41
+ :desc => "Framework to use") { |all, choices, default, other|
42
+ ask_with_other("Framework", all, choices, default, other)
43
+ }
44
+ input(:runtime, :from_given => find_by_name("runtime"),
45
+ :desc => "Runtime to use") { |all, choices, default, other|
46
+ ask_with_other("Runtime", all, choices, default, other)
47
+ }
48
+ input(:command, :desc => "Startup command for standalone app") {
49
+ ask("Startup command")
50
+ }
51
+ input :plan, :default => "D100",
52
+ :desc => "Application plan (e.g. D100, P200)"
53
+ input :start, :type => :boolean, :default => true,
54
+ :desc => "Start app after pushing?"
55
+ input :restart, :type => :boolean, :default => true,
56
+ :desc => "Restart app after updating?"
57
+ input(:create_services, :type => :boolean,
58
+ :desc => "Interactively create services?") {
59
+ line unless quiet?
60
+ ask "Create services for application?", :default => false
61
+ }
62
+ input(:bind_services, :type => :boolean,
63
+ :desc => "Interactively bind services?") {
64
+ ask "Bind other services to application?", :default => false
65
+ }
66
+ def push
67
+ name = input[:name]
68
+ path = File.expand_path(input[:path])
69
+
70
+ if app = client.app_by_name(name)
71
+ sync_app(app, path)
72
+ else
73
+ create_app(name, path)
74
+ end
75
+ end
76
+
77
+ def sync_app(app, path)
78
+ upload_app(app, path)
79
+
80
+ diff = {}
81
+
82
+ if input.given?(:memory)
83
+ mem = megabytes(input[:memory])
84
+
85
+ if mem != app.memory
86
+ diff[:memory] = [app.memory, mem]
87
+ app.memory = mem
88
+ end
89
+ end
90
+
91
+ if input.given?(:instances)
92
+ instances = input[:instances]
93
+
94
+ if instances != app.total_instances
95
+ diff[:instances] = [app.total_instances, instances]
96
+ app.total_instances = instances
97
+ end
98
+ end
99
+
100
+ if input.given?(:framework)
101
+ all_frameworks = client.frameworks
102
+
103
+ framework = input[:framework, all_frameworks, all_frameworks]
104
+
105
+ if framework != app.framework
106
+ diff[:framework] = [app.framework.name, framework.name]
107
+ app.framework = framework
108
+ end
109
+ end
110
+
111
+ if input.given?(:runtime)
112
+ all_runtimes = client.runtimes
113
+
114
+ runtime = input[:runtime, all_runtimes, all_runtimes]
115
+
116
+ if runtime != app.runtime
117
+ diff[:runtime] = [app.runtime.name, runtime.name]
118
+ app.runtime = runtime
119
+ end
120
+ end
121
+
122
+ if input.given?(:command) && input[:command] != app.command
123
+ command = input[:command]
124
+
125
+ if command != app.command
126
+ diff[:command] = [app.command, command]
127
+ app.command = command
128
+ end
129
+ end
130
+
131
+ if input.given?(:plan) && v2?
132
+ production = !!(input[:plan] =~ /^p/i)
133
+
134
+ if production != app.production
135
+ diff[:production] = [bool(app.production), bool(production)]
136
+ app.production = production
137
+ end
138
+ end
139
+
140
+ unless diff.empty?
141
+ line "Changes:"
142
+
143
+ indented do
144
+ diff.each do |name, change|
145
+ old, new = change
146
+ line "#{c(name, :name)}: #{old} #{c("->", :dim)} #{new}"
147
+ end
148
+ end
149
+
150
+ with_progress("Updating #{c(app.name, :name)}") do
151
+ app.update!
152
+ end
153
+ end
154
+
155
+ if input[:restart] && app.started?
156
+ invoke :restart, :app => app
157
+ end
158
+ end
159
+
160
+ def create_app(name, path)
161
+ app = client.app
162
+ app.name = name
163
+ app.space = client.current_space if client.current_space
164
+ app.total_instances = input[:instances]
165
+ app.production = !!(input[:plan] =~ /^p/i) if v2?
166
+
167
+ detector = VMC::Detector.new(client, path)
168
+ all_frameworks = detector.all_frameworks
169
+ all_runtimes = detector.all_runtimes
170
+
171
+ if detected_framework = detector.detect_framework
172
+ framework = input[
173
+ :framework,
174
+ all_frameworks,
175
+ [detected_framework],
176
+ detected_framework,
177
+ :other
178
+ ]
179
+ else
180
+ framework = input[:framework, all_frameworks, all_frameworks]
181
+ end
182
+
183
+
184
+ if framework.name == "standalone"
185
+ detected_runtimes = detector.detect_runtimes
186
+ else
187
+ detected_runtimes = detector.runtimes(framework)
188
+ end
189
+
190
+ if detected_runtimes.size == 1
191
+ default_runtime = detected_runtimes.first
192
+ end
193
+
194
+ if detected_runtimes.empty?
195
+ runtime = input[:runtime, all_runtimes, all_runtimes]
196
+ else
197
+ runtime = input[
198
+ :runtime,
199
+ all_runtimes,
200
+ detected_runtimes,
201
+ default_runtime,
202
+ :other
203
+ ]
204
+ end
205
+
206
+
207
+ fail "Invalid framework '#{input[:framework]}'" unless framework
208
+ fail "Invalid runtime '#{input[:runtime]}'" unless runtime
209
+
210
+ app.framework = framework
211
+ app.runtime = runtime
212
+
213
+ app.command = input[:command] if framework.name == "standalone"
214
+
215
+ default_memory = detector.suggested_memory(framework) || 64
216
+ app.memory = megabytes(input[:memory, human_mb(default_memory)])
217
+
218
+ app = filter(:create_app, app)
219
+
220
+ with_progress("Creating #{c(app.name, :name)}") do
221
+ app.create!
222
+ end
223
+
224
+ line unless quiet?
225
+
226
+ url = input[:url, name]
227
+
228
+ mapped_url = false
229
+ until !url || mapped_url
230
+ begin
231
+ invoke :map, :app => app, :url => url
232
+ mapped_url = true
233
+ rescue CFoundry::RouteHostTaken, CFoundry::UriAlreadyTaken => e
234
+ line c(e.description, :bad)
235
+ line
236
+
237
+ input.forget(:url)
238
+ url = input[:url, name]
239
+
240
+ # version bumps on v1 even though mapping fails
241
+ app.invalidate! unless v2?
242
+ end
243
+ end
244
+
245
+ bindings = []
246
+
247
+ if input[:create_services] && !force?
248
+ while true
249
+ invoke :create_service, { :app => app }, :plan => :interact
250
+ break unless ask "Create another service?", :default => false
251
+ end
252
+ end
253
+
254
+ if input[:bind_services] && !force?
255
+ instances = client.service_instances
256
+
257
+ while true
258
+ invoke :bind_service, :app => app
259
+
260
+ break if (instances - app.services).empty?
261
+
262
+ break unless ask("Bind another service?", :default => false)
263
+ end
264
+ end
265
+
266
+ app = filter(:push_app, app)
267
+
268
+ begin
269
+ upload_app(app, path)
270
+ rescue
271
+ err "Upload failed. Try again with 'vmc push'."
272
+ raise
273
+ end
274
+
275
+ invoke :start, :app => app if input[:start]
276
+ end
277
+
278
+ private
279
+
280
+ def upload_app(app, path)
281
+ with_progress("Uploading #{c(app.name, :name)}") do
282
+ app.upload(path)
283
+ end
284
+ end
285
+
286
+ def bool(b)
287
+ if b
288
+ c("true", :yes)
289
+ else
290
+ c("false", :no)
291
+ end
292
+ end
293
+
294
+ def url_choices(name)
295
+ if v2?
296
+ client.current_space.domains.sort_by(&:name).collect do |d|
297
+ # TODO: check availability
298
+ "#{name}.#{d.name}"
299
+ end
300
+ else
301
+ ["#{name}.#{target_base}"]
302
+ end
303
+ end
304
+
305
+ def target_base
306
+ client.target.sub(/^https?:\/\/([^\.]+\.)?(.+)\/?/, '\2')
307
+ end
308
+
309
+ def ask_with_other(message, all, choices, default, other)
310
+ choices = choices.sort_by(&:name)
311
+ choices << other if other
312
+
313
+ opts = {
314
+ :choices => choices,
315
+ :display => proc { |x|
316
+ if other && x == other
317
+ "other"
318
+ else
319
+ x.name
320
+ end
321
+ }
322
+ }
323
+
324
+ opts[:default] = default if default
325
+
326
+ res = ask(message, opts)
327
+
328
+ if other && res == other
329
+ opts[:choices] = all
330
+ res = ask(message, opts)
331
+ end
332
+
333
+ res
334
+ end
335
+ end
336
+ end