cf 0.1.5 → 0.6.0.rc1

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 (140) hide show
  1. data/LICENSE +1277 -30
  2. data/Rakefile +12 -1
  3. data/bin/cf +0 -3
  4. data/lib/cf.rb +6 -0
  5. data/lib/cf/cli.rb +389 -190
  6. data/lib/cf/cli/app/app.rb +45 -0
  7. data/lib/cf/cli/app/apps.rb +99 -0
  8. data/lib/cf/cli/app/base.rb +90 -0
  9. data/lib/cf/cli/app/crashes.rb +42 -0
  10. data/lib/cf/cli/app/delete.rb +95 -0
  11. data/lib/cf/cli/app/deprecated.rb +11 -0
  12. data/lib/cf/cli/app/env.rb +78 -0
  13. data/lib/cf/cli/app/files.rb +137 -0
  14. data/lib/cf/cli/app/health.rb +26 -0
  15. data/lib/cf/cli/app/instances.rb +53 -0
  16. data/lib/cf/cli/app/logs.rb +76 -0
  17. data/lib/cf/cli/app/push.rb +105 -0
  18. data/lib/cf/cli/app/push/create.rb +149 -0
  19. data/lib/cf/cli/app/push/interactions.rb +94 -0
  20. data/lib/cf/cli/app/push/sync.rb +64 -0
  21. data/lib/cf/cli/app/rename.rb +35 -0
  22. data/lib/cf/cli/app/restart.rb +20 -0
  23. data/lib/cf/cli/app/scale.rb +69 -0
  24. data/lib/cf/cli/app/start.rb +143 -0
  25. data/lib/cf/cli/app/stats.rb +67 -0
  26. data/lib/cf/cli/app/stop.rb +27 -0
  27. data/lib/cf/cli/domain/base.rb +8 -0
  28. data/lib/cf/cli/domain/domains.rb +40 -0
  29. data/lib/cf/cli/domain/map.rb +55 -0
  30. data/lib/cf/cli/domain/unmap.rb +56 -0
  31. data/lib/cf/cli/help.rb +15 -0
  32. data/lib/cf/cli/interactive.rb +105 -0
  33. data/lib/cf/cli/organization/base.rb +12 -0
  34. data/lib/cf/cli/organization/create.rb +32 -0
  35. data/lib/cf/cli/organization/delete.rb +73 -0
  36. data/lib/cf/cli/organization/org.rb +45 -0
  37. data/lib/cf/cli/organization/orgs.rb +35 -0
  38. data/lib/cf/cli/organization/rename.rb +36 -0
  39. data/lib/cf/cli/route/base.rb +8 -0
  40. data/lib/cf/cli/route/map.rb +70 -0
  41. data/lib/cf/cli/route/routes.rb +26 -0
  42. data/lib/cf/cli/route/unmap.rb +62 -0
  43. data/lib/cf/cli/service/base.rb +8 -0
  44. data/lib/cf/cli/service/bind.rb +44 -0
  45. data/lib/cf/cli/service/create.rb +107 -0
  46. data/lib/cf/cli/service/delete.rb +82 -0
  47. data/lib/cf/cli/service/rename.rb +35 -0
  48. data/lib/cf/cli/service/service.rb +40 -0
  49. data/lib/cf/cli/service/services.rb +99 -0
  50. data/lib/cf/cli/service/unbind.rb +38 -0
  51. data/lib/cf/cli/space/base.rb +19 -0
  52. data/lib/cf/cli/space/create.rb +63 -0
  53. data/lib/cf/cli/space/delete.rb +95 -0
  54. data/lib/cf/cli/space/rename.rb +39 -0
  55. data/lib/cf/cli/space/space.rb +64 -0
  56. data/lib/cf/cli/space/spaces.rb +55 -0
  57. data/lib/cf/cli/space/switch.rb +16 -0
  58. data/lib/cf/cli/start/base.rb +93 -0
  59. data/lib/cf/cli/start/colors.rb +13 -0
  60. data/lib/cf/cli/start/info.rb +124 -0
  61. data/lib/cf/cli/start/login.rb +94 -0
  62. data/lib/cf/cli/start/logout.rb +17 -0
  63. data/lib/cf/cli/start/target.rb +69 -0
  64. data/lib/cf/cli/start/target_interactions.rb +37 -0
  65. data/lib/cf/cli/start/targets.rb +16 -0
  66. data/lib/cf/cli/user/base.rb +29 -0
  67. data/lib/cf/cli/user/create.rb +39 -0
  68. data/lib/cf/cli/user/passwd.rb +43 -0
  69. data/lib/cf/cli/user/register.rb +42 -0
  70. data/lib/cf/cli/user/users.rb +32 -0
  71. data/lib/cf/constants.rb +10 -7
  72. data/lib/cf/detect.rb +113 -48
  73. data/lib/cf/errors.rb +17 -0
  74. data/lib/cf/plugin.rb +28 -12
  75. data/lib/cf/spacing.rb +89 -0
  76. data/lib/cf/spec_helper.rb +1 -0
  77. data/lib/cf/test_support.rb +6 -0
  78. data/lib/cf/version.rb +1 -1
  79. data/spec/assets/hello-sinatra/Gemfile +3 -0
  80. data/spec/assets/hello-sinatra/Gemfile.lock +17 -0
  81. data/spec/assets/hello-sinatra/config.ru +3 -0
  82. data/spec/assets/hello-sinatra/fat-cat-makes-app-larger.png +0 -0
  83. data/spec/assets/hello-sinatra/main.rb +6 -0
  84. data/spec/assets/specker_runner/specker_runner_input.rb +6 -0
  85. data/spec/assets/specker_runner/specker_runner_pause.rb +5 -0
  86. data/spec/cf/cli/app/base_spec.rb +17 -0
  87. data/spec/cf/cli/app/delete_spec.rb +188 -0
  88. data/spec/cf/cli/app/instances_spec.rb +65 -0
  89. data/spec/cf/cli/app/push/create_spec.rb +661 -0
  90. data/spec/cf/cli/app/push_spec.rb +369 -0
  91. data/spec/cf/cli/app/rename_spec.rb +104 -0
  92. data/spec/cf/cli/app/scale_spec.rb +75 -0
  93. data/spec/cf/cli/app/start_spec.rb +208 -0
  94. data/spec/cf/cli/app/stats_spec.rb +68 -0
  95. data/spec/cf/cli/domain/map_spec.rb +130 -0
  96. data/spec/cf/cli/domain/unmap_spec.rb +69 -0
  97. data/spec/cf/cli/organization/orgs_spec.rb +108 -0
  98. data/spec/cf/cli/organization/rename_spec.rb +113 -0
  99. data/spec/cf/cli/route/map_spec.rb +121 -0
  100. data/spec/cf/cli/route/unmap_spec.rb +155 -0
  101. data/spec/cf/cli/service/bind_spec.rb +25 -0
  102. data/spec/cf/cli/service/delete_spec.rb +22 -0
  103. data/spec/cf/cli/service/rename_spec.rb +105 -0
  104. data/spec/cf/cli/service/service_spec.rb +23 -0
  105. data/spec/cf/cli/service/unbind_spec.rb +25 -0
  106. data/spec/cf/cli/space/create_spec.rb +93 -0
  107. data/spec/cf/cli/space/rename_spec.rb +102 -0
  108. data/spec/cf/cli/space/spaces_spec.rb +104 -0
  109. data/spec/cf/cli/space/switch_space_spec.rb +55 -0
  110. data/spec/cf/cli/start/info_spec.rb +160 -0
  111. data/spec/cf/cli/start/login_spec.rb +142 -0
  112. data/spec/cf/cli/start/logout_spec.rb +50 -0
  113. data/spec/cf/cli/start/target_spec.rb +123 -0
  114. data/spec/cf/cli/user/create_spec.rb +54 -0
  115. data/spec/cf/cli/user/passwd_spec.rb +102 -0
  116. data/spec/cf/cli/user/register_spec.rb +140 -0
  117. data/spec/cf/cli_spec.rb +442 -0
  118. data/spec/cf/detect_spec.rb +54 -0
  119. data/spec/console_app_specker/console_app_specker_matchers_spec.rb +173 -0
  120. data/spec/console_app_specker/specker_runner_spec.rb +167 -0
  121. data/spec/features/account_lifecycle_spec.rb +85 -0
  122. data/spec/features/login_spec.rb +66 -0
  123. data/spec/features/push_flow_spec.rb +125 -0
  124. data/spec/features/switching_targets_spec.rb +32 -0
  125. data/spec/spec_helper.rb +72 -0
  126. data/spec/support/command_helper.rb +81 -0
  127. data/spec/support/config_helper.rb +15 -0
  128. data/spec/support/console_app_specker_matchers.rb +86 -0
  129. data/spec/support/fake_home_dir.rb +55 -0
  130. data/spec/support/interact_helper.rb +29 -0
  131. data/spec/support/shared_examples/errors.rb +40 -0
  132. data/spec/support/shared_examples/input.rb +14 -0
  133. data/spec/support/specker_runner.rb +80 -0
  134. data/spec/support/tracking_expector.rb +71 -0
  135. metadata +427 -66
  136. data/lib/cf/cli/app.rb +0 -595
  137. data/lib/cf/cli/command.rb +0 -444
  138. data/lib/cf/cli/dots.rb +0 -133
  139. data/lib/cf/cli/service.rb +0 -112
  140. data/lib/cf/cli/user.rb +0 -71
@@ -0,0 +1,137 @@
1
+ require "thread"
2
+ require "cf/cli/app/base"
3
+
4
+ module CF::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 "cf/cli/app/base"
2
+
3
+ module CF::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 "cf/cli/app/base"
2
+
3
+ module CF::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 "cf/cli/app/base"
2
+
3
+ module CF::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
70
+ line unless body.empty?
71
+ rescue CFoundry::NotFound
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,105 @@
1
+ require "cf/cli/app/base"
2
+ require "cf/cli/app/push/sync"
3
+ require "cf/cli/app/push/create"
4
+ require "cf/cli/app/push/interactions"
5
+
6
+ module CF::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 given == "none"
19
+ given
20
+ else
21
+ app.space.domain_by_name(given) ||
22
+ fail_unknown("domain", given)
23
+ end
24
+ }
25
+ input :memory, :desc => "Memory limit"
26
+ input :instances, :desc => "Number of instances to run", :type => :integer
27
+ input :framework, :desc => "Framework to use",
28
+ :from_given => by_name(:framework)
29
+ input :runtime, :desc => "Runtime to use",
30
+ :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 :stack, :desc => "Stack to use", :default => nil,
37
+ :from_given => by_name(:stack)
38
+ input :create_services, :desc => "Interactively create services?",
39
+ :type => :boolean, :default => proc { force? ? false : interact }
40
+ input :bind_services, :desc => "Interactively bind services?",
41
+ :type => :boolean, :default => proc { force? ? false : interact }
42
+ interactions PushInteractions
43
+
44
+ def push
45
+ name = input[:name]
46
+ path = File.expand_path(input[:path])
47
+ app = client.app_by_name(name)
48
+
49
+ if app
50
+ sync_app(app, path)
51
+ else
52
+ setup_new_app(path)
53
+ end
54
+ end
55
+
56
+ def sync_app(app, path)
57
+ upload_app(app, path)
58
+ apply_changes(app)
59
+ display_changes(app)
60
+ commit_changes(app)
61
+ end
62
+
63
+ def setup_new_app(path)
64
+ self.path = path
65
+ app = create_app(get_inputs)
66
+ map_route(app)
67
+ create_services(app)
68
+ bind_services(app)
69
+ upload_app(app, path)
70
+ start_app(app)
71
+ end
72
+
73
+ private
74
+
75
+ def url_choices(name)
76
+ client.current_space.domains.sort_by(&:name).collect do |d|
77
+ # TODO: check availability
78
+ "#{name}.#{d.name}"
79
+ end
80
+ end
81
+
82
+ def upload_app(app, path)
83
+ app = filter(:push_app, app)
84
+
85
+ with_progress("Uploading #{c(app.name, :name)}") do
86
+ app.upload(path)
87
+ end
88
+ rescue
89
+ err "Upload failed. Try again with 'cf push'."
90
+ raise
91
+ end
92
+
93
+ def wrap_message_format_errors
94
+ yield
95
+ rescue CFoundry::MessageParseError => e
96
+ md = e.description.match /Field: ([^,]+)/
97
+ field = md[1]
98
+
99
+ case field
100
+ when "buildpack"
101
+ fail "Buildpack must be a public git repository URI."
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,149 @@
1
+ require "cf/detect"
2
+
3
+ module CF::App
4
+ module Create
5
+ attr_accessor :input
6
+ attr_writer :path
7
+
8
+ def get_inputs
9
+ inputs = {}
10
+ inputs[:name] = input[:name]
11
+ inputs[:total_instances] = input[:instances]
12
+ inputs[:space] = client.current_space if client.current_space
13
+
14
+ inputs[:production] = !!(input[:plan] =~ /^p/i)
15
+
16
+ inputs[:buildpack] = input[:buildpack]
17
+ inputs[:command] = input[:command] if input.has?(:command) || !has_procfile?
18
+
19
+ detected = detector.detected
20
+ human_mb = human_mb((detected && detected.memory_suggestion) || 64)
21
+ inputs[:memory] = megabytes(input[:memory, human_mb])
22
+
23
+ inputs[:stack] = input[:stack]
24
+
25
+ inputs
26
+ end
27
+
28
+ def determine_framework
29
+ return input[:framework] if input.has?(:framework)
30
+
31
+ if (detected_framework = detector.detect_framework)
32
+ input[:framework, [detected_framework], detected_framework, :other]
33
+ else
34
+ input[:framework, detector.all_frameworks, nil, nil]
35
+ end
36
+ end
37
+
38
+ def determine_runtime(framework)
39
+ return input[:runtime] if input.has?(:runtime)
40
+
41
+ detected_runtimes =
42
+ if framework.name == "standalone"
43
+ detector.detect_runtimes
44
+ else
45
+ detector.runtimes(framework)
46
+ end
47
+
48
+ default_runtime = detected_runtimes.size == 1 ? detected_runtimes.first : nil
49
+
50
+ if detected_runtimes.empty?
51
+ input[:runtime, detector.all_runtimes, nil, nil]
52
+ else
53
+ input[:runtime, detected_runtimes, default_runtime, :other]
54
+ end
55
+ end
56
+
57
+ def create_app(inputs)
58
+ app = client.app
59
+
60
+ inputs.each { |key, value| app.send(:"#{key}=", value) }
61
+
62
+ app = filter(:create_app, app)
63
+
64
+ with_progress("Creating #{c(app.name, :name)}") do
65
+ wrap_message_format_errors do
66
+ begin
67
+ app.create!
68
+ rescue CFoundry::NotAuthorized
69
+ fail "You need the Project Developer role in #{b(client.current_space.name)} to push."
70
+ end
71
+ end
72
+ end
73
+
74
+ app
75
+ end
76
+
77
+ def map_route(app)
78
+ line unless quiet?
79
+
80
+ host = input[:host, app.name]
81
+ domain = input[:domain, app]
82
+
83
+ mapped_url = false
84
+ until domain == "none" || !domain || mapped_url
85
+ begin
86
+ host = "" if host == "none"
87
+ invoke :map, :app => app, :host => host, :domain => domain
88
+ mapped_url = true
89
+ rescue CFoundry::RouteHostTaken, CFoundry::UriAlreadyTaken => e
90
+ raise if force?
91
+
92
+ line c(e.description, :bad)
93
+ line
94
+
95
+ input.forget(:host)
96
+ input.forget(:domain)
97
+
98
+ host = input[:host, app.name]
99
+ domain = input[:domain, app]
100
+ end
101
+ end
102
+ end
103
+
104
+ def create_services(app)
105
+ return unless input[:create_services]
106
+
107
+ while true
108
+ invoke :create_service, { :app => app }, :plan => :interact
109
+ break unless ask("Create another service?", :default => false)
110
+ end
111
+ end
112
+
113
+ def bind_services(app)
114
+ return unless input[:bind_services]
115
+
116
+ while true
117
+ invoke :bind_service, :app => app
118
+ break if (all_instances - app.services).empty?
119
+ break unless ask("Bind another service?", :default => false)
120
+ end
121
+ end
122
+
123
+ def start_app(app)
124
+ invoke :start, :app => app if input[:start]
125
+ end
126
+
127
+ private
128
+
129
+ def has_procfile?
130
+ File.exists?("#@path/Procfile")
131
+ end
132
+
133
+ def can_have_custom_start_command?(framework)
134
+ framework.name == "standalone"
135
+ end
136
+
137
+ def all_instances
138
+ @all_instances ||= client.service_instances
139
+ end
140
+
141
+ def detector
142
+ @detector ||= CF::Detector.new(client, @path)
143
+ end
144
+
145
+ def target_base
146
+ client.target.sub(/^https?:\/\/([^\.]+\.)?(.+)\/?/, '\2')
147
+ end
148
+ end
149
+ end