jdc 0.1.2 → 0.2.0

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 (151) hide show
  1. data/LICENSE +1277 -24
  2. data/Rakefile +13 -0
  3. data/bin/jdc +12 -2
  4. data/lib/admin/README.md +15 -0
  5. data/lib/admin/curl.rb +60 -0
  6. data/lib/admin/guid.rb +89 -0
  7. data/lib/admin/plugin.rb +6 -0
  8. data/lib/admin/service_auth_token.rb +94 -0
  9. data/lib/admin/service_broker/add.rb +47 -0
  10. data/lib/admin/service_broker/service_brokers.rb +24 -0
  11. data/lib/admin/set_quota.rb +44 -0
  12. data/lib/console/README.md +8 -0
  13. data/lib/console/console.rb +187 -0
  14. data/lib/console/plugin.rb +33 -0
  15. data/lib/jdc/cli/app/app.rb +43 -0
  16. data/lib/jdc/cli/app/apps.rb +87 -0
  17. data/lib/jdc/cli/app/base.rb +72 -0
  18. data/lib/jdc/cli/app/delete.rb +95 -0
  19. data/lib/jdc/cli/app/deprecated.rb +11 -0
  20. data/lib/jdc/cli/app/env.rb +78 -0
  21. data/lib/jdc/cli/app/events.rb +45 -0
  22. data/lib/jdc/cli/app/files.rb +137 -0
  23. data/lib/jdc/cli/app/health.rb +26 -0
  24. data/lib/jdc/cli/app/instances.rb +53 -0
  25. data/lib/jdc/cli/app/logs.rb +76 -0
  26. data/lib/jdc/cli/app/push/create.rb +108 -0
  27. data/lib/jdc/cli/app/push/interactions.rb +86 -0
  28. data/lib/jdc/cli/app/push/sync.rb +57 -0
  29. data/lib/jdc/cli/app/push.rb +103 -0
  30. data/lib/jdc/cli/app/rename.rb +35 -0
  31. data/lib/jdc/cli/app/restart.rb +31 -0
  32. data/lib/jdc/cli/app/scale.rb +63 -0
  33. data/lib/jdc/cli/app/start.rb +161 -0
  34. data/lib/jdc/cli/app/stats.rb +67 -0
  35. data/lib/jdc/cli/app/stop.rb +27 -0
  36. data/lib/jdc/cli/domain/base.rb +9 -0
  37. data/lib/jdc/cli/domain/domains.rb +40 -0
  38. data/lib/jdc/cli/domain/map.rb +55 -0
  39. data/lib/jdc/cli/domain/unmap.rb +56 -0
  40. data/lib/jdc/cli/help.rb +15 -0
  41. data/lib/jdc/cli/interactive.rb +105 -0
  42. data/lib/jdc/cli/login_requirements.rb +15 -0
  43. data/lib/jdc/cli/organization/base.rb +14 -0
  44. data/lib/jdc/cli/organization/create.rb +37 -0
  45. data/lib/jdc/cli/organization/delete.rb +63 -0
  46. data/lib/jdc/cli/organization/org.rb +45 -0
  47. data/lib/jdc/cli/organization/orgs.rb +30 -0
  48. data/lib/jdc/cli/organization/rename.rb +37 -0
  49. data/lib/jdc/cli/populators/base.rb +16 -0
  50. data/lib/jdc/cli/populators/organization.rb +32 -0
  51. data/lib/jdc/cli/populators/populator_methods.rb +64 -0
  52. data/lib/jdc/cli/populators/space.rb +33 -0
  53. data/lib/jdc/cli/populators/target.rb +13 -0
  54. data/lib/jdc/cli/route/base.rb +9 -0
  55. data/lib/jdc/cli/route/delete.rb +28 -0
  56. data/lib/jdc/cli/route/map.rb +68 -0
  57. data/lib/jdc/cli/route/routes.rb +26 -0
  58. data/lib/jdc/cli/route/unmap.rb +56 -0
  59. data/lib/jdc/cli/service/base.rb +9 -0
  60. data/lib/jdc/cli/service/bind.rb +44 -0
  61. data/lib/jdc/cli/service/create.rb +159 -0
  62. data/lib/jdc/cli/service/delete.rb +83 -0
  63. data/lib/jdc/cli/service/rename.rb +36 -0
  64. data/lib/jdc/cli/service/service.rb +42 -0
  65. data/lib/jdc/cli/service/service_instance_helper.rb +99 -0
  66. data/lib/jdc/cli/service/services.rb +111 -0
  67. data/lib/jdc/cli/service/unbind.rb +37 -0
  68. data/lib/jdc/cli/space/base.rb +29 -0
  69. data/lib/jdc/cli/space/create.rb +67 -0
  70. data/lib/jdc/cli/space/delete.rb +56 -0
  71. data/lib/jdc/cli/space/rename.rb +38 -0
  72. data/lib/jdc/cli/space/space.rb +66 -0
  73. data/lib/jdc/cli/space/spaces.rb +57 -0
  74. data/lib/jdc/cli/space/switch.rb +19 -0
  75. data/lib/jdc/cli/start/base.rb +41 -0
  76. data/lib/jdc/cli/start/colors.rb +13 -0
  77. data/lib/jdc/cli/start/target.rb +50 -0
  78. data/lib/jdc/cli/start/target_prettifier.rb +17 -0
  79. data/lib/jdc/cli/start/targets.rb +16 -0
  80. data/lib/jdc/cli/user/base.rb +30 -0
  81. data/lib/jdc/cli/user/create.rb +52 -0
  82. data/lib/jdc/cli/user/passwd.rb +37 -0
  83. data/lib/jdc/cli/user/register.rb +43 -0
  84. data/lib/jdc/cli/user/users.rb +32 -0
  85. data/lib/jdc/cli.rb +544 -0
  86. data/lib/jdc/constants.rb +11 -0
  87. data/lib/jdc/errors.rb +19 -0
  88. data/lib/jdc/object_extensions.rb +15 -0
  89. data/lib/jdc/plugin.rb +56 -0
  90. data/lib/jdc/spacing.rb +89 -0
  91. data/lib/jdc/spec_helper.rb +1 -0
  92. data/lib/jdc/test_support.rb +6 -0
  93. data/lib/jdc/version.rb +3 -0
  94. data/lib/jdc.rb +15 -2
  95. data/lib/manifests/errors.rb +35 -0
  96. data/lib/manifests/loader/builder.rb +39 -0
  97. data/lib/manifests/loader/normalizer.rb +145 -0
  98. data/lib/manifests/loader/resolver.rb +79 -0
  99. data/lib/manifests/loader.rb +31 -0
  100. data/lib/manifests/manifests.rb +344 -0
  101. data/lib/manifests/plugin.rb +140 -0
  102. data/lib/micro/README.md +9 -0
  103. data/lib/micro/errors.rb +4 -0
  104. data/lib/{jdc → micro}/micro.rb +15 -15
  105. data/lib/micro/plugin.rb +197 -0
  106. data/lib/micro/switcher/base.rb +79 -0
  107. data/lib/{jdc/micro → micro}/switcher/darwin.rb +5 -3
  108. data/lib/{jdc/micro → micro}/switcher/dummy.rb +1 -1
  109. data/lib/micro/switcher/linux.rb +16 -0
  110. data/lib/{jdc/micro → micro}/switcher/windows.rb +5 -5
  111. data/lib/{jdc/micro → micro}/vmrun.rb +26 -19
  112. data/lib/tasks/gem_release.rake +42 -0
  113. data/lib/tunnel/README.md +29 -0
  114. data/{config → lib/tunnel/config}/clients.yml +2 -2
  115. data/lib/tunnel/helper-app/Gemfile +10 -0
  116. data/lib/tunnel/helper-app/Gemfile.lock +48 -0
  117. data/{caldecott_helper → lib/tunnel/helper-app}/server.rb +5 -5
  118. data/lib/tunnel/plugin.rb +183 -0
  119. data/lib/tunnel/tunnel.rb +295 -0
  120. metadata +319 -89
  121. data/README.md +0 -102
  122. data/config/micro/paths.yml +0 -22
  123. data/config/micro/refresh_ip.rb +0 -20
  124. data/lib/cli/commands/admin.rb +0 -58
  125. data/lib/cli/commands/apps.rb +0 -1129
  126. data/lib/cli/commands/base.rb +0 -228
  127. data/lib/cli/commands/manifest.rb +0 -56
  128. data/lib/cli/commands/micro.rb +0 -115
  129. data/lib/cli/commands/misc.rb +0 -126
  130. data/lib/cli/commands/services.rb +0 -178
  131. data/lib/cli/commands/user.rb +0 -14
  132. data/lib/cli/config.rb +0 -173
  133. data/lib/cli/console_helper.rb +0 -170
  134. data/lib/cli/core_ext.rb +0 -122
  135. data/lib/cli/errors.rb +0 -19
  136. data/lib/cli/frameworks.rb +0 -265
  137. data/lib/cli/manifest_helper.rb +0 -302
  138. data/lib/cli/runner.rb +0 -505
  139. data/lib/cli/services_helper.rb +0 -84
  140. data/lib/cli/tunnel_helper.rb +0 -332
  141. data/lib/cli/usage.rb +0 -86
  142. data/lib/cli/version.rb +0 -7
  143. data/lib/cli/zip_util.rb +0 -77
  144. data/lib/cli.rb +0 -53
  145. data/lib/jdc/client.rb +0 -457
  146. data/lib/jdc/const.rb +0 -25
  147. data/lib/jdc/micro/switcher/base.rb +0 -97
  148. data/lib/jdc/micro/switcher/linux.rb +0 -16
  149. data/lib/jdc/signature/version.rb +0 -27
  150. data/lib/jdc/signer.rb +0 -13
  151. data/lib/jdc/timer.rb +0 -12
@@ -0,0 +1,108 @@
1
+ module JDC::App
2
+ module Create
3
+ attr_accessor :input
4
+ attr_writer :path
5
+
6
+ def get_inputs
7
+ inputs = {}
8
+ inputs[:name] = input[:name]
9
+ inputs[:total_instances] = input[:instances]
10
+ inputs[:space] = client.current_space if client.current_space
11
+
12
+ inputs[:buildpack] = input[:buildpack]
13
+ inputs[:command] = input[:command] if input.has?(:command) || !has_procfile?
14
+
15
+ inputs[:memory] = megabytes(input[:memory, human_mb(256)])
16
+ inputs[:stack] = input[:stack]
17
+
18
+ inputs
19
+ end
20
+
21
+ def create_app(inputs)
22
+ app = client.app
23
+
24
+ inputs.each { |key, value| app.send(:"#{key}=", value) }
25
+ finalize
26
+
27
+ app = filter(:create_app, app)
28
+
29
+ with_progress("Creating #{c(app.name, :name)}") do
30
+ wrap_message_format_errors do
31
+ begin
32
+ app.create!
33
+ rescue JFoundry::NotAuthorized
34
+ fail "You need the Project Developer role in #{b(client.current_space.name)} to push."
35
+ end
36
+ end
37
+ end
38
+
39
+ app
40
+ end
41
+
42
+ def map_route(app)
43
+ line unless quiet?
44
+
45
+ host = input[:host, app.name]
46
+ finalize
47
+ domain = input[:domain, app]
48
+ finalize
49
+
50
+ mapped_url = false
51
+ until domain == "none" || !domain || mapped_url
52
+ begin
53
+ host = "" if host == "none"
54
+ invoke :map, :app => app, :host => host, :domain => domain
55
+ mapped_url = true
56
+ rescue JFoundry::RouteHostTaken, JFoundry::UriAlreadyTaken => e
57
+ raise if force?
58
+
59
+ line c(e.description, :bad)
60
+ line
61
+
62
+ input.forget(:host)
63
+ input.forget(:domain)
64
+
65
+ host = input[:host, app.name]
66
+ domain = input[:domain, app]
67
+ end
68
+ end
69
+ end
70
+
71
+ def create_services(app)
72
+ return unless input[:create_services]
73
+ finalize
74
+ while true
75
+ invoke :create_service, { :app => app }, :plan => :interact
76
+ break unless ask("Create another service?", :default => false)
77
+ end
78
+ end
79
+
80
+ def bind_services(app)
81
+ return unless input[:bind_services]
82
+
83
+ while true
84
+ invoke :bind_service, :app => app
85
+ break if (all_instances - app.services).empty?
86
+ break unless ask("Bind another service?", :default => false)
87
+ end
88
+ end
89
+
90
+ def start_app(app)
91
+ invoke :start, :app => app if input[:start]
92
+ end
93
+
94
+ private
95
+
96
+ def has_procfile?
97
+ File.exists?("#@path/Procfile")
98
+ end
99
+
100
+ def all_instances
101
+ @all_instances ||= client.service_instances
102
+ end
103
+
104
+ def target_base
105
+ client.target.sub(/^https?:\/\/([^\.]+\.)?(.+)\/?/, '\2')
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,86 @@
1
+ module JDC::App
2
+ module PushInteractions
3
+ def ask_name
4
+ ask("Name")
5
+ end
6
+
7
+ def ask_host(name)
8
+ ask "Subdomain", :choices => [name, "none"],
9
+ :default => name,
10
+ :allow_other => true
11
+ end
12
+
13
+ def ask_domain(app)
14
+ choices = app.space.domains
15
+
16
+ options = {
17
+ :choices => choices + ["none"],
18
+ :display => proc { |choice| choice.is_a?(String) ? choice : choice.name },
19
+ :allow_other => true
20
+ }
21
+
22
+ options[:default] = choices.first
23
+
24
+ ask "Domain", options
25
+ end
26
+
27
+ def ask_memory(default)
28
+ ask("Memory Limit",
29
+ :choices => memory_choices,
30
+ :allow_other => true,
31
+ :default => default || "128M")
32
+ end
33
+
34
+ def ask_instances
35
+ ask("Instances", :default => 1)
36
+ end
37
+
38
+ def ask_command
39
+ command = ask("Custom startup command", :default => "none")
40
+
41
+ if command != "none"
42
+ command
43
+ end
44
+ end
45
+
46
+ def ask_create_services
47
+ line unless quiet?
48
+ ask "Create services for application?", :default => false
49
+ end
50
+
51
+ def ask_bind_services
52
+ return if all_instances.empty?
53
+
54
+ ask "Bind other services to application?", :default => false
55
+ end
56
+
57
+ private
58
+
59
+ def ask_with_other(message, all, choices, default, other)
60
+ choices = choices.sort_by(&:name)
61
+ choices << other if other
62
+
63
+ opts = {
64
+ :choices => choices,
65
+ :display => proc { |x|
66
+ if other && x == other
67
+ "other"
68
+ else
69
+ x.name
70
+ end
71
+ }
72
+ }
73
+
74
+ opts[:default] = default if default
75
+
76
+ res = ask(message, opts)
77
+
78
+ if other && res == other
79
+ opts[:choices] = all
80
+ res = ask(message, opts)
81
+ end
82
+
83
+ res
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,57 @@
1
+ module JDC::App
2
+ module Sync
3
+ def apply_changes(app)
4
+ app.memory = megabytes(input[:memory]) if input.has?(:memory)
5
+ app.total_instances = input[:instances] if input.has?(:instances)
6
+ app.command = input[:command] if input.has?(:command)
7
+ app.buildpack = input[:buildpack] if input.has?(:buildpack)
8
+ end
9
+
10
+ def display_changes(app)
11
+ return unless app.changed?
12
+
13
+ line "Changes:"
14
+
15
+ indented do
16
+ app.changes.each do |attr, (old, new)|
17
+ line "#{c(attr, :name)}: #{diff_str(attr, old)} -> #{diff_str(attr, new)}"
18
+ end
19
+ end
20
+ end
21
+
22
+ def commit_changes(app)
23
+ if app.changed?
24
+ with_progress("Updating #{c(app.name, :name)}") do
25
+ wrap_message_format_errors do
26
+ app.update!
27
+ end
28
+ end
29
+ end
30
+
31
+ if input[:restart] && app.started?
32
+ invoke :restart, :app => app
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def diff_str(attr, val)
39
+ case attr
40
+ when :memory
41
+ human_mb(val)
42
+ when :command, :buildpack
43
+ "'#{val}'"
44
+ else
45
+ val
46
+ end
47
+ end
48
+
49
+ def bool(b)
50
+ if b
51
+ c("true", :yes)
52
+ else
53
+ c("false", :no)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,103 @@
1
+ require "jdc/cli/app/base"
2
+ require "jdc/cli/app/push/sync"
3
+ require "jdc/cli/app/push/create"
4
+ require "jdc/cli/app/push/interactions"
5
+
6
+ module JDC::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 :command, :desc => "Startup command", :default => nil
28
+ input :plan, :desc => "Application plan"
29
+ input :start, :desc => "Start app after pushing?", :default => true
30
+ input :restart, :desc => "Restart app after updating?", :default => true
31
+ input :buildpack, :desc => "Custom buildpack URL", :default => nil
32
+ input :stack, :desc => "Stack to use", :default => nil,
33
+ :from_given => by_name(:stack)
34
+ input :create_services, :desc => "Interactively create services?",
35
+ :type => :boolean, :default => proc { force? ? false : interact }
36
+ input :bind_services, :desc => "Interactively bind services?",
37
+ :type => :boolean, :default => proc { force? ? false : interact }
38
+ interactions PushInteractions
39
+
40
+ def push
41
+ name = input[:name]
42
+ path = File.expand_path(input[:path])
43
+ app = client.app_by_name(name)
44
+
45
+ if app
46
+ sync_app(app, path)
47
+ else
48
+ setup_new_app(path)
49
+ end
50
+ end
51
+
52
+ def sync_app(app, path)
53
+ upload_app(app, path)
54
+ apply_changes(app)
55
+ display_changes(app)
56
+ commit_changes(app)
57
+
58
+ warn "\n#{c(app.name, :name)} is currently stopped, start it with 'jdc start'" unless app.started?
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)
74
+ client.current_space.domains.sort_by(&:name).collect do |d|
75
+ # TODO: check availability
76
+ "#{name}.#{d.name}"
77
+ end
78
+ end
79
+
80
+ def upload_app(app, path)
81
+ app = filter(:push_app, app)
82
+
83
+ with_progress("Uploading #{c(app.name, :name)}") do
84
+ app.upload(path)
85
+ end
86
+ rescue
87
+ err "Upload failed. Try again with 'jdc push'."
88
+ raise
89
+ end
90
+
91
+ def wrap_message_format_errors
92
+ yield
93
+ rescue JFoundry::MessageParseError => e
94
+ md = e.description.match /Field: ([^,]+)/
95
+ field = md[1]
96
+
97
+ case field
98
+ when "buildpack"
99
+ fail "Buildpack must be a public git repository URI."
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,35 @@
1
+ require "jdc/cli/app/base"
2
+
3
+ module JDC::App
4
+ class Rename < Base
5
+ desc "Rename an application"
6
+ group :apps, :manage
7
+ input :app, :desc => "Application to rename", :argument => :optional,
8
+ :from_given => by_name(:app)
9
+ input :name, :desc => "New application name", :argument => :optional
10
+ def rename
11
+ app = input[:app]
12
+ name = input[:name]
13
+
14
+ app.name = name
15
+
16
+ with_progress("Renaming to #{c(name, :name)}") do
17
+ app.update!
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def ask_app
24
+ apps = client.apps
25
+ fail "No applications." if apps.empty?
26
+
27
+ ask("Rename which application?", :choices => apps.sort_by(&:name),
28
+ :display => proc(&:name))
29
+ end
30
+
31
+ def ask_name
32
+ ask("New name")
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ require "jdc/cli/app/base"
2
+
3
+ module JDC::App
4
+ class Restart < Base
5
+ desc "Stop and start an application"
6
+ group :apps, :manage
7
+ input :apps, :desc => "Applications to start", :argument => :splat,
8
+ :singular => :app, :from_given => by_name(:app)
9
+ input :debug_mode, :desc => "Debug mode to start in", :aliases => "-d"
10
+ input :all, :desc => "Restart all applications", :default => false
11
+
12
+ ############# Uncomment to complete 50543607
13
+ #input :command, :desc => "Command to restart application", :default => nil
14
+
15
+ def restart
16
+ invoke :stop, :all => input[:all], :apps => input[:apps]
17
+
18
+ line unless quiet?
19
+
20
+ input[:apps].each do |app|
21
+ unless input[:command].nil?
22
+ app.command = input[:command]
23
+ end
24
+ app.update!
25
+ end
26
+
27
+ invoke :start, :all => input[:all], :apps => input[:apps],
28
+ :debug_mode => input[:debug_mode]
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,63 @@
1
+ require "jdc/cli/app/base"
2
+
3
+ module JDC::App
4
+ class Scale < Base
5
+ desc "Update the instances/memory limit for an application"
6
+ group :apps, :info
7
+ input :app, :desc => "Application to update", :argument => true,
8
+ :from_given => by_name(:app)
9
+ input :instances, :desc => "Number of instances to run",
10
+ :type => :numeric
11
+ input :memory, :desc => "Memory limit"
12
+ input :disk, :desc => "Disk quota"
13
+ input :restart, :desc => "Restart app after updating?", :default => true
14
+
15
+ def scale
16
+ app = input[:app]
17
+
18
+ if input.has?(:instances)
19
+ instances = input[:instances, app.total_instances]
20
+ end
21
+
22
+ if input.has?(:memory)
23
+ memory = input[:memory, app.memory]
24
+ end
25
+
26
+ if input.has?(:disk)
27
+ disk = input[:disk, human_mb(app.disk_quota)]
28
+ end
29
+
30
+ unless instances || memory || disk
31
+ instances = input[:instances, app.total_instances]
32
+ memory = input[:memory, app.memory]
33
+ end
34
+
35
+ app.total_instances = instances if input.has?(:instances)
36
+ app.memory = megabytes(memory) if input.has?(:memory)
37
+ app.disk_quota = megabytes(disk) if input.has?(:disk)
38
+
39
+ fail "No changes!" unless app.changed?
40
+
41
+ with_progress("Scaling #{c(app.name, :name)}") do
42
+ app.update!
43
+ end
44
+
45
+ needs_restart = app.changes.key?(:memory) || app.changes.key?(:disk_quota)
46
+
47
+ if needs_restart && app.started? && input[:restart]
48
+ invoke :restart, :app => app
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def ask_instances(default)
55
+ ask("Instances", :default => default)
56
+ end
57
+
58
+ def ask_memory(default)
59
+ ask("Memory Limit", :choices => memory_choices,
60
+ :default => human_mb(default), :allow_other => true)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,161 @@
1
+ require "jdc/cli/app/base"
2
+
3
+ module JDC::App
4
+ class Start < Base
5
+ APP_CHECK_LIMIT = 60
6
+
7
+ desc "Start an application"
8
+ group :apps, :manage
9
+ input :apps, :desc => "Applications to start", :argument => :splat,
10
+ :singular => :app, :from_given => by_name(:app)
11
+ input :debug_mode, :desc => "Debug mode to start in", :aliases => "-d"
12
+ input :all, :desc => "Start all applications", :default => false
13
+ def start
14
+ apps = input[:all] ? client.apps : input[:apps]
15
+ fail "No applications given." if apps.empty?
16
+
17
+ spaced(apps) do |app|
18
+ app = filter(:start_app, app)
19
+
20
+ switch_mode(app, input[:debug_mode])
21
+
22
+ if app.started?
23
+ err "Application #{b(app.name)} is already started."
24
+ next
25
+ end
26
+
27
+ log = start_app(app)
28
+ stream_start_log(log) if log
29
+ check_application(app)
30
+
31
+ if !app.debug_mode.nil? && app.debug_mode != "none" && !quiet?
32
+ line
33
+ invoke :instances, :app => app
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def start_app(app)
41
+ log = nil
42
+ with_progress("Preparing to start #{c(app.name, :name)}") do
43
+ app.start! do |url|
44
+ log = url
45
+ end
46
+ end
47
+ log
48
+ end
49
+
50
+ def stream_start_log(log)
51
+ offset = 0
52
+
53
+ while true
54
+ begin
55
+ client.stream_url(log + "&tail&tail_offset=#{offset}") do |out|
56
+ offset += out.size
57
+ print out
58
+ end
59
+ rescue Timeout::Error
60
+ end
61
+ end
62
+ rescue JFoundry::APIError
63
+ end
64
+
65
+ # set app debug mode, ensuring it's valid, and shutting it down
66
+ def switch_mode(app, mode)
67
+ mode = "run" if mode == "" # no value given
68
+
69
+ return false if app.debug == mode
70
+
71
+ if mode == "none"
72
+ with_progress("Removing debug mode") do
73
+ app.debug = mode
74
+ app.stop! if app.started?
75
+ end
76
+
77
+ return true
78
+ end
79
+
80
+ with_progress("Switching mode to #{c(mode, :name)}") do |s|
81
+ app.debug = mode
82
+ app.stop! if app.started?
83
+ end
84
+ end
85
+
86
+ def check_application(app)
87
+ if app.debug == "suspend"
88
+ line "Application is in suspended debugging mode."
89
+ line "It will wait for you to attach to it before starting."
90
+ return
91
+ end
92
+
93
+ print("Checking status of app '#{c(app.name, :name)}'...")
94
+
95
+ seconds = 0
96
+ @first_time_after_staging_succeeded = true
97
+
98
+ begin
99
+ instances = []
100
+ while true
101
+ if any_instance_flapping?(instances) || seconds == APP_CHECK_LIMIT
102
+ err "Push unsuccessful."
103
+ return
104
+ end
105
+
106
+ begin
107
+ return unless instances = app.instances
108
+
109
+ indented { print_instances_summary(instances) }
110
+
111
+ if all_instances_running?(instances)
112
+ line "#{c("Push successful! App '#{app.name}' available at http://#{app.host}.#{app.domain}", :good)}"
113
+ return
114
+ end
115
+ rescue JFoundry::NotStaged
116
+ print (".")
117
+ end
118
+
119
+ sleep 1
120
+ seconds += 1
121
+ end
122
+ rescue JFoundry::StagingError
123
+ err "Application failed to stage"
124
+ end
125
+ end
126
+
127
+ def all_instances_running?(instances)
128
+ instances.all? { |i| i.state == "RUNNING" }
129
+ end
130
+
131
+ def any_instance_flapping?(instances)
132
+ instances.any? { |i| i.state == "FLAPPING" }
133
+ end
134
+
135
+ def print_instances_summary(instances)
136
+
137
+ if @first_time_after_staging_succeeded
138
+ line
139
+ @first_time_after_staging_succeeded = false
140
+ end
141
+
142
+ counts = Hash.new { 0 }
143
+ instances.each do |i|
144
+ counts[i.state] += 1
145
+ end
146
+
147
+ states = []
148
+ %w{RUNNING STARTING DOWN FLAPPING}.each do |state|
149
+ if (num = counts[state]) > 0
150
+ states << "#{b(num)} #{c(state.downcase, state_color(state))}"
151
+ end
152
+ end
153
+
154
+ total = instances.count
155
+ running = counts["RUNNING"].to_s.rjust(total.to_s.size)
156
+
157
+ ratio = "#{running}#{d(" of ")}#{total} instances running"
158
+ line "#{ratio} (#{states.join(", ")})"
159
+ end
160
+ end
161
+ end