af 0.3.22 → 0.5.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 (157) hide show
  1. checksums.yaml +14 -6
  2. data/LICENSE +1277 -24
  3. data/Rakefile +24 -87
  4. data/bin/af +7 -2
  5. data/lib/af/version.rb +3 -0
  6. data/lib/vmc.rb +7 -2
  7. data/lib/vmc/cli.rb +475 -0
  8. data/lib/vmc/cli/app/app.rb +45 -0
  9. data/lib/vmc/cli/app/apps.rb +105 -0
  10. data/lib/vmc/cli/app/base.rb +82 -0
  11. data/lib/vmc/cli/app/crashes.rb +46 -0
  12. data/lib/vmc/cli/app/delete.rb +95 -0
  13. data/lib/vmc/cli/app/deprecated.rb +11 -0
  14. data/lib/vmc/cli/app/env.rb +78 -0
  15. data/lib/vmc/cli/app/files.rb +137 -0
  16. data/lib/vmc/cli/app/health.rb +26 -0
  17. data/lib/vmc/cli/app/instances.rb +53 -0
  18. data/lib/vmc/cli/app/logs.rb +76 -0
  19. data/lib/vmc/cli/app/push.rb +107 -0
  20. data/lib/vmc/cli/app/push/create.rb +150 -0
  21. data/lib/vmc/cli/app/push/interactions.rb +100 -0
  22. data/lib/vmc/cli/app/push/sync.rb +64 -0
  23. data/lib/vmc/cli/app/rename.rb +39 -0
  24. data/lib/vmc/cli/app/restart.rb +20 -0
  25. data/lib/vmc/cli/app/scale.rb +71 -0
  26. data/lib/vmc/cli/app/start.rb +93 -0
  27. data/lib/vmc/cli/app/stats.rb +67 -0
  28. data/lib/vmc/cli/app/stop.rb +27 -0
  29. data/lib/vmc/cli/domain/base.rb +12 -0
  30. data/lib/vmc/cli/domain/domains.rb +40 -0
  31. data/lib/vmc/cli/domain/map.rb +55 -0
  32. data/lib/vmc/cli/domain/unmap.rb +56 -0
  33. data/lib/vmc/cli/help.rb +16 -0
  34. data/lib/vmc/cli/interactive.rb +105 -0
  35. data/lib/vmc/cli/organization/base.rb +14 -0
  36. data/lib/vmc/cli/organization/create.rb +32 -0
  37. data/lib/vmc/cli/organization/delete.rb +73 -0
  38. data/lib/vmc/cli/organization/org.rb +45 -0
  39. data/lib/vmc/cli/organization/orgs.rb +35 -0
  40. data/lib/vmc/cli/organization/rename.rb +36 -0
  41. data/lib/vmc/cli/route/base.rb +12 -0
  42. data/lib/vmc/cli/route/map.rb +80 -0
  43. data/lib/vmc/cli/route/routes.rb +26 -0
  44. data/lib/vmc/cli/route/unmap.rb +94 -0
  45. data/lib/vmc/cli/service/base.rb +8 -0
  46. data/lib/vmc/cli/service/bind.rb +44 -0
  47. data/lib/vmc/cli/service/create.rb +126 -0
  48. data/lib/vmc/cli/service/delete.rb +86 -0
  49. data/lib/vmc/cli/service/rename.rb +35 -0
  50. data/lib/vmc/cli/service/service.rb +42 -0
  51. data/lib/vmc/cli/service/services.rb +115 -0
  52. data/lib/vmc/cli/service/unbind.rb +38 -0
  53. data/lib/vmc/cli/space/base.rb +21 -0
  54. data/lib/vmc/cli/space/create.rb +56 -0
  55. data/lib/vmc/cli/space/delete.rb +95 -0
  56. data/lib/vmc/cli/space/rename.rb +39 -0
  57. data/lib/vmc/cli/space/space.rb +64 -0
  58. data/lib/vmc/cli/space/spaces.rb +55 -0
  59. data/lib/vmc/cli/space/take.rb +16 -0
  60. data/lib/vmc/cli/start/base.rb +80 -0
  61. data/lib/vmc/cli/start/colors.rb +13 -0
  62. data/lib/vmc/cli/start/info.rb +122 -0
  63. data/lib/vmc/cli/start/login.rb +92 -0
  64. data/lib/vmc/cli/start/logout.rb +13 -0
  65. data/lib/vmc/cli/start/target.rb +64 -0
  66. data/lib/vmc/cli/start/target_interactions.rb +37 -0
  67. data/lib/vmc/cli/start/targets.rb +16 -0
  68. data/lib/vmc/cli/user/base.rb +29 -0
  69. data/lib/vmc/cli/user/create.rb +39 -0
  70. data/lib/vmc/cli/user/delete.rb +25 -0
  71. data/lib/vmc/cli/user/passwd.rb +50 -0
  72. data/lib/vmc/cli/user/register.rb +42 -0
  73. data/lib/vmc/cli/user/users.rb +32 -0
  74. data/lib/vmc/constants.rb +13 -0
  75. data/lib/vmc/detect.rb +134 -0
  76. data/lib/vmc/errors.rb +17 -0
  77. data/lib/vmc/plugin.rb +56 -0
  78. data/lib/vmc/spacing.rb +89 -0
  79. data/lib/vmc/spec_helper.rb +1 -0
  80. data/lib/vmc/test_support.rb +4 -0
  81. data/lib/vmc/test_support/command_helper.rb +32 -0
  82. data/lib/vmc/test_support/common_input_examples.rb +14 -0
  83. data/lib/vmc/test_support/fake_home_dir.rb +16 -0
  84. data/lib/vmc/test_support/interact_helper.rb +29 -0
  85. data/lib/vmc/version.rb +3 -0
  86. data/spec/assets/hello-sinatra/Gemfile +3 -0
  87. data/spec/assets/hello-sinatra/main.rb +6 -0
  88. data/spec/features/new_user_flow_spec.rb +71 -0
  89. data/spec/spec_helper.rb +63 -0
  90. data/spec/vmc/cli/app/base_spec.rb +17 -0
  91. data/spec/vmc/cli/app/delete_spec.rb +188 -0
  92. data/spec/vmc/cli/app/instances_spec.rb +65 -0
  93. data/spec/vmc/cli/app/push/create_spec.rb +571 -0
  94. data/spec/vmc/cli/app/push_spec.rb +369 -0
  95. data/spec/vmc/cli/app/rename_spec.rb +104 -0
  96. data/spec/vmc/cli/app/scale_spec.rb +81 -0
  97. data/spec/vmc/cli/app/stats_spec.rb +62 -0
  98. data/spec/vmc/cli/domain/map_spec.rb +140 -0
  99. data/spec/vmc/cli/domain/unmap_spec.rb +73 -0
  100. data/spec/vmc/cli/organization/orgs_spec.rb +108 -0
  101. data/spec/vmc/cli/organization/rename_spec.rb +113 -0
  102. data/spec/vmc/cli/route/map_spec.rb +138 -0
  103. data/spec/vmc/cli/route/unmap_spec.rb +215 -0
  104. data/spec/vmc/cli/service/bind_spec.rb +25 -0
  105. data/spec/vmc/cli/service/delete_spec.rb +22 -0
  106. data/spec/vmc/cli/service/rename_spec.rb +105 -0
  107. data/spec/vmc/cli/service/service_spec.rb +23 -0
  108. data/spec/vmc/cli/service/unbind_spec.rb +25 -0
  109. data/spec/vmc/cli/space/rename_spec.rb +102 -0
  110. data/spec/vmc/cli/space/spaces_spec.rb +104 -0
  111. data/spec/vmc/cli/start/info_spec.rb +153 -0
  112. data/spec/vmc/cli/start/login_spec.rb +71 -0
  113. data/spec/vmc/cli/user/create_spec.rb +54 -0
  114. data/spec/vmc/cli/user/passwd_spec.rb +102 -0
  115. data/spec/vmc/cli/user/register_spec.rb +148 -0
  116. data/spec/vmc/cli_spec.rb +448 -0
  117. data/spec/vmc/detect_spec.rb +54 -0
  118. metadata +231 -124
  119. data/README.md +0 -155
  120. data/caldecott_helper/Gemfile +0 -10
  121. data/caldecott_helper/Gemfile.lock +0 -48
  122. data/caldecott_helper/server.rb +0 -43
  123. data/config/clients.yml +0 -17
  124. data/config/micro/offline.conf +0 -2
  125. data/config/micro/paths.yml +0 -22
  126. data/config/micro/refresh_ip.rb +0 -20
  127. data/lib/cli.rb +0 -48
  128. data/lib/cli/commands/admin.rb +0 -81
  129. data/lib/cli/commands/apps.rb +0 -1358
  130. data/lib/cli/commands/base.rb +0 -233
  131. data/lib/cli/commands/manifest.rb +0 -56
  132. data/lib/cli/commands/micro.rb +0 -115
  133. data/lib/cli/commands/misc.rb +0 -147
  134. data/lib/cli/commands/services.rb +0 -217
  135. data/lib/cli/commands/user.rb +0 -70
  136. data/lib/cli/config.rb +0 -176
  137. data/lib/cli/console_helper.rb +0 -163
  138. data/lib/cli/core_ext.rb +0 -122
  139. data/lib/cli/errors.rb +0 -19
  140. data/lib/cli/file_helper.rb +0 -123
  141. data/lib/cli/frameworks.rb +0 -265
  142. data/lib/cli/manifest_helper.rb +0 -316
  143. data/lib/cli/runner.rb +0 -633
  144. data/lib/cli/services_helper.rb +0 -104
  145. data/lib/cli/tunnel_helper.rb +0 -336
  146. data/lib/cli/usage.rb +0 -129
  147. data/lib/cli/version.rb +0 -7
  148. data/lib/cli/zip_util.rb +0 -102
  149. data/lib/vmc/client.rb +0 -574
  150. data/lib/vmc/const.rb +0 -27
  151. data/lib/vmc/micro.rb +0 -56
  152. data/lib/vmc/micro/switcher/base.rb +0 -97
  153. data/lib/vmc/micro/switcher/darwin.rb +0 -19
  154. data/lib/vmc/micro/switcher/dummy.rb +0 -15
  155. data/lib/vmc/micro/switcher/linux.rb +0 -16
  156. data/lib/vmc/micro/switcher/windows.rb +0 -31
  157. data/lib/vmc/micro/vmrun.rb +0 -158
@@ -0,0 +1,137 @@
1
+ require "thread"
2
+ require "vmc/cli/app/base"
3
+
4
+ module VMC::App
5
+ class Files < Base
6
+ desc "Print out an app's file contents"
7
+ group :apps, :info, :hidden => true
8
+ input :app, :desc => "Application to inspect the files of",
9
+ :argument => true, :from_given => by_name(:app)
10
+ input :path, :desc => "Path of file to read", :argument => :optional,
11
+ :default => "/"
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, :desc => "Application to inspect the files of",
39
+ :argument => true, :from_given => by_name(:app)
40
+ input :path, :desc => "Path of directory to list", :argument => :optional,
41
+ :default => "/"
42
+ def files
43
+ app = input[:app]
44
+ path = input[:path]
45
+
46
+ if quiet?
47
+ files =
48
+ with_progress("Getting file listing") do
49
+ app.files(*path.split("/"))
50
+ end
51
+
52
+ files.each do |file|
53
+ line file.join("/")
54
+ end
55
+ else
56
+ invoke :file, :app => app, :path => path
57
+ end
58
+ rescue CFoundry::NotFound
59
+ fail "Invalid path #{b(path)} for app #{b(app.name)}"
60
+ rescue CFoundry::FileError => e
61
+ fail e.description
62
+ end
63
+
64
+ desc "Stream an app's file contents"
65
+ group :apps, :info, :hidden => true
66
+ input :app, :desc => "Application to inspect the files of",
67
+ :argument => true, :from_given => by_name(:app)
68
+ input :path, :desc => "Path of file to stream", :argument => :optional
69
+ def tail
70
+ app = input[:app]
71
+
72
+ lines = Queue.new
73
+ max_len = 0
74
+
75
+ if path = input[:path]
76
+ max_len = path.size
77
+ app.instances.each do |i|
78
+ Thread.new do
79
+ stream_path(lines, i, path.split("/"))
80
+ end
81
+ end
82
+ else
83
+ app.instances.each do |i|
84
+ i.files("logs").each do |path|
85
+ len = path.join("/").size
86
+ max_len = len if len > max_len
87
+
88
+ Thread.new do
89
+ stream_path(lines, i, path)
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ while line = lines.pop
96
+ instance, path, log = line
97
+
98
+ unless log.end_with?("\n")
99
+ log += i("%") if color?
100
+ log += "\n"
101
+ end
102
+
103
+ print "\##{c(instance.id, :instance)} "
104
+ print "#{c(path.join("/").ljust(max_len), :name)} "
105
+ print log
106
+ end
107
+ rescue CFoundry::NotFound
108
+ fail "Invalid path #{b(path)} for app #{b(app.name)}"
109
+ rescue CFoundry::FileError => e
110
+ fail e.description
111
+ end
112
+
113
+ def stream_path(lines, instance, path)
114
+ if verbose?
115
+ lines << [instance, path, c("streaming...", :good) + "\n"]
116
+ end
117
+
118
+ instance.stream_file(*path) do |contents|
119
+ contents.each_line do |line|
120
+ lines << [instance, path, line]
121
+ end
122
+ end
123
+
124
+ lines << [instance, path, c("end of file", :bad) + "\n"]
125
+ rescue Timeout::Error
126
+ if verbose?
127
+ lines << [
128
+ instance,
129
+ path,
130
+ c("timed out; reconnecting...", :bad) + "\n"
131
+ ]
132
+ end
133
+
134
+ retry
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,26 @@
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, :desc => "Applications to start", :argument => :splat,
8
+ :singular => :app, :from_given => by_name(:app)
9
+ def health
10
+ apps = input[:apps]
11
+ fail "No applications given." if apps.empty?
12
+
13
+ health =
14
+ with_progress("Getting health status") do
15
+ apps.collect { |a| [a, app_status(a)] }
16
+ end
17
+
18
+ line unless quiet?
19
+
20
+ spaced(health) do |app, status|
21
+ start_line "#{c(app.name, :name)}: " unless quiet?
22
+ puts status
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,53 @@
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, :desc => "Applications whose instances to list",
8
+ :argument => :splat, :singular => :app,
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
+ line unless quiet?
21
+
22
+ spaced(instances.sort { |a, b| a.id.to_i <=> b.id.to_i }) do |i|
23
+ if quiet?
24
+ line i.id
25
+ else
26
+ display_instance(i)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def display_instance(i)
35
+ start_line "instance #{c("\##{i.id}", :instance)}: "
36
+ puts "#{b(c(i.state.downcase, state_color(i.state)))}"
37
+
38
+ indented do
39
+ if s = i.since
40
+ line "started: #{c(s.strftime("%F %r"), :neutral)}"
41
+ end
42
+
43
+ if d = i.debugger
44
+ line "debugger: port #{b(d[:port])} at #{b(d[:ip])}"
45
+ end
46
+
47
+ if c = i.console
48
+ line "console: port #{b(c[:port])} at #{b(c[:ip])}"
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,76 @@
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, :desc => "Application to get the logs of", :argument => true,
8
+ :from_given => by_name(:app)
9
+ input :instance, :desc => "Instance of application to get the logs of",
10
+ :default => "0"
11
+ input :all, :desc => "Get logs for every instance", :default => false
12
+ def logs
13
+ app = input[:app]
14
+
15
+ instances =
16
+ if input[:all] || input[:instance] == "all"
17
+ app.instances
18
+ else
19
+ app.instances.select { |i| i.id == input[:instance] }
20
+ end
21
+
22
+ if instances.empty?
23
+ if input[:all]
24
+ fail "No instances found."
25
+ else
26
+ fail "Instance #{app.name} \##{input[:instance]} not found."
27
+ end
28
+ end
29
+
30
+ spaced(instances) do |i|
31
+ show_instance_logs(app, i)
32
+ end
33
+ end
34
+
35
+ desc "Print out the logs for an app's crashed instances"
36
+ group :apps, :info, :hidden => true
37
+ input :app, :desc => "Application to get the logs of", :argument => true,
38
+ :from_given => by_name(:app)
39
+ def crashlogs
40
+ app = input[:app]
41
+
42
+ crashes = app.crashes
43
+
44
+ fail "No crashed instances found." if crashes.empty?
45
+
46
+ most_recent = crashes.sort_by(&:since).last
47
+ show_instance_logs(app, most_recent)
48
+ end
49
+
50
+ def show_instance_logs(app, i)
51
+ return unless i.id
52
+
53
+ logs =
54
+ with_progress(
55
+ "Getting logs for #{c(app.name, :name)} " +
56
+ c("\##{i.id}", :instance)) do
57
+ i.files("logs")
58
+ end
59
+
60
+ line unless quiet?
61
+
62
+ spaced(logs) do |log|
63
+ begin
64
+ body =
65
+ with_progress("Reading " + b(log.join("/"))) do |s|
66
+ i.file(*log)
67
+ end
68
+
69
+ lines body unless body.nil?
70
+ line unless body.nil?
71
+ rescue CFoundry::NotFound
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,107 @@
1
+ require "vmc/cli/app/base"
2
+ require "vmc/cli/app/push/sync"
3
+ require "vmc/cli/app/push/create"
4
+ require "vmc/cli/app/push/interactions"
5
+
6
+ module VMC::App
7
+ class Push < Base
8
+ include Sync
9
+ include Create
10
+
11
+ desc "Push an application, syncing changes if it exists"
12
+ group :apps, :manage
13
+ input :name, :desc => "Application name", :argument => :optional
14
+ input :path, :desc => "Path containing the bits", :default => "."
15
+ input :host, :desc => "Subdomain for the app's URL"
16
+ input :domain, :desc => "Domain for the app",
17
+ :from_given => proc { |given, app|
18
+ if !v2? || given == "none"
19
+ given
20
+ else
21
+ app.space.domain_by_name(given) ||
22
+ fail_unknown("domain", given)
23
+ end
24
+ }
25
+ input :infra, :desc => "Infrastructure to use", :from_given => by_name(:infra)
26
+ input :url, :desc => "URL to bind to app"
27
+ input :memory, :desc => "Memory limit"
28
+ input :instances, :desc => "Number of instances to run", :type => :integer
29
+ input :framework, :desc => "Framework to use", :from_given => by_name(:framework)
30
+ input :runtime, :desc => "Runtime to use", :from_given => by_name(:runtime)
31
+ input :command, :desc => "Startup command"
32
+ input :plan, :desc => "Application plan", :default => "D100"
33
+ input :start, :desc => "Start app after pushing?", :default => true
34
+ input :restart, :desc => "Restart app after updating?", :default => true
35
+ input :buildpack, :desc => "Custom buildpack URL", :default => nil
36
+ input :create_services, :desc => "Interactively create services?",
37
+ :type => :boolean, :default => proc { force? ? false : interact }
38
+ input :bind_services, :desc => "Interactively bind services?",
39
+ :type => :boolean, :default => proc { force? ? false : interact }
40
+ interactions PushInteractions
41
+
42
+ def push
43
+ name = input[:name]
44
+ path = File.expand_path(input[:path])
45
+ app = client.app_by_name(name)
46
+
47
+ if app
48
+ sync_app(app, path)
49
+ else
50
+ setup_new_app(path)
51
+ end
52
+ end
53
+
54
+ def sync_app(app, path)
55
+ upload_app(app, path)
56
+ apply_changes(app)
57
+ display_changes(app)
58
+ commit_changes(app)
59
+ end
60
+
61
+ def setup_new_app(path)
62
+ self.path = path
63
+ app = create_app(get_inputs)
64
+ # map_route(app)
65
+ create_services(app)
66
+ bind_services(app)
67
+ upload_app(app, path)
68
+ start_app(app)
69
+ end
70
+
71
+ private
72
+
73
+ def url_choices(name, infra)
74
+ if v2?
75
+ client.current_space.domains.sort_by(&:name).collect do |d|
76
+ # TODO: check availability
77
+ "#{name}.#{d.name}"
78
+ end
79
+ else
80
+ %W(#{name}.#{infra.base})
81
+ end
82
+ end
83
+
84
+ def upload_app(app, path)
85
+ app = filter(:push_app, app)
86
+
87
+ with_progress("Uploading #{c(app.name, :name)}") do
88
+ app.upload(path)
89
+ end
90
+ rescue
91
+ err "Upload failed. Try again with 'af push'."
92
+ raise
93
+ end
94
+
95
+ def wrap_message_format_errors
96
+ yield
97
+ rescue CFoundry::MessageParseError => e
98
+ md = e.description.match /Field: ([^,]+)/
99
+ field = md[1]
100
+
101
+ case field
102
+ when "buildpack"
103
+ fail "Buildpack must be a public git repository URI."
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,150 @@
1
+ require "vmc/detect"
2
+
3
+ module VMC::App
4
+ module Create
5
+ attr_accessor :input
6
+ attr_writer :path
7
+
8
+ def get_inputs
9
+ inputs = {}
10
+ inputs[:name] = name = input[:name]
11
+ inputs[:infra] = infra = determine_infra
12
+ inputs[:url] = input[:url, name, infra]
13
+ inputs[:uris] = [inputs[:url]]
14
+ inputs[:total_instances] = input[:instances]
15
+ inputs[:space] = client.current_space if client.current_space
16
+ inputs[:production] = !!(input[:plan] =~ /^p/i) if v2?
17
+ inputs[:framework] = framework = determine_framework
18
+ inputs[:command] = input[:command] if can_have_custom_start_command?(framework)
19
+ inputs[:runtime] = determine_runtime(framework)
20
+ inputs[:buildpack] = input[:buildpack] if v2?
21
+
22
+ human_mb = human_mb(detector.suggested_memory(framework) || 64)
23
+ inputs[:memory] = megabytes(input[:memory, human_mb])
24
+
25
+ inputs
26
+ end
27
+
28
+ def determine_infra
29
+ return input[:infra] if input.has?(:infra)
30
+
31
+ input[:infra, detector.all_infras, nil, nil]
32
+ end
33
+
34
+ def determine_framework
35
+ return input[:framework] if input.has?(:framework)
36
+
37
+ if (detected_framework = detector.detect_framework)
38
+ input[:framework, [detected_framework], detected_framework, :other]
39
+ else
40
+ input[:framework, detector.all_frameworks, nil, nil]
41
+ end
42
+ end
43
+
44
+ def determine_runtime(framework)
45
+ return input[:runtime] if input.has?(:runtime)
46
+
47
+ detected_runtimes =
48
+ if framework.name == "standalone"
49
+ detector.detect_runtimes
50
+ else
51
+ detector.runtimes(framework)
52
+ end
53
+
54
+ default_runtime = detected_runtimes.size == 1 ? detected_runtimes.first : nil
55
+
56
+ if detected_runtimes.empty?
57
+ input[:runtime, detector.all_runtimes, nil, nil]
58
+ else
59
+ input[:runtime, detected_runtimes, default_runtime, :other]
60
+ end
61
+ end
62
+
63
+ def create_app(inputs)
64
+ app = client.app
65
+
66
+ inputs.each { |key, value| app.send(:"#{key}=", value) }
67
+
68
+ app = filter(:create_app, app)
69
+
70
+ with_progress("Creating #{c(app.name, :name)}") do
71
+ wrap_message_format_errors do
72
+ app.create!
73
+ end
74
+ end
75
+
76
+ app
77
+ end
78
+
79
+ def map_route(app)
80
+ line unless quiet?
81
+
82
+ host = input[:host, app.name] if v2?
83
+ domain = input[:domain, app]
84
+
85
+ mapped_url = false
86
+ until domain == "none" || !domain || mapped_url
87
+ begin
88
+ host = "" if host == "none"
89
+ invoke :map, :app => app, :host => host, :domain => domain
90
+ mapped_url = true
91
+ rescue CFoundry::RouteHostTaken, CFoundry::UriAlreadyTaken => e
92
+ raise if force?
93
+
94
+ line c(e.description, :bad)
95
+ line
96
+
97
+ input.forget(:host) if v2?
98
+ input.forget(:domain)
99
+
100
+ host = input[:host, app.name] if v2?
101
+ domain = input[:domain, app]
102
+
103
+ # version bumps on v1 even though mapping fails
104
+ app.invalidate! unless v2?
105
+ end
106
+ end
107
+ end
108
+
109
+ def create_services(app)
110
+ return unless input[:create_services]
111
+
112
+ while true
113
+ invoke :create_service, { :app => app }, :plan => :interact
114
+ break unless ask("Create another service?", :default => false)
115
+ end
116
+ end
117
+
118
+ def bind_services(app)
119
+ return unless input[:bind_services]
120
+
121
+ while true
122
+ invoke :bind_service, :app => app
123
+ break if (all_instances - app.services).empty?
124
+ break unless ask("Bind another service?", :default => false)
125
+ end
126
+ end
127
+
128
+ def start_app(app)
129
+ invoke :start, :app => app if input[:start]
130
+ end
131
+
132
+ private
133
+
134
+ def can_have_custom_start_command?(framework)
135
+ %w(standalone buildpack).include?(framework.name)
136
+ end
137
+
138
+ def all_instances
139
+ @all_instances ||= client.service_instances
140
+ end
141
+
142
+ def detector
143
+ @detector ||= VMC::Detector.new(client, @path)
144
+ end
145
+
146
+ def target_base
147
+ client.target.sub(/^https?:\/\/([^\.]+\.)?(.+)\/?/, '\2')
148
+ end
149
+ end
150
+ end