engineyard-serverside 2.0.7 → 2.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/lib/engineyard-serverside.rb +0 -1
  2. data/lib/engineyard-serverside/cli.rb +44 -42
  3. data/lib/engineyard-serverside/configuration.rb +55 -4
  4. data/lib/engineyard-serverside/dependency_manager.rb +17 -0
  5. data/lib/engineyard-serverside/dependency_manager/base.rb +65 -0
  6. data/lib/engineyard-serverside/dependency_manager/bundler.rb +124 -0
  7. data/lib/engineyard-serverside/dependency_manager/bundler_lock.rb +155 -0
  8. data/lib/engineyard-serverside/dependency_manager/legacy_helpers.rb +24 -0
  9. data/lib/engineyard-serverside/dependency_manager/npm.rb +16 -0
  10. data/lib/engineyard-serverside/deploy.rb +86 -178
  11. data/lib/engineyard-serverside/deprecation.rb +11 -1
  12. data/lib/engineyard-serverside/paths.rb +6 -0
  13. data/lib/engineyard-serverside/propagator.rb +2 -2
  14. data/lib/engineyard-serverside/rails_assets.rb +152 -0
  15. data/lib/engineyard-serverside/rails_assets/strategy.rb +197 -0
  16. data/lib/engineyard-serverside/server.rb +5 -0
  17. data/lib/engineyard-serverside/servers.rb +19 -7
  18. data/lib/engineyard-serverside/shell.rb +7 -5
  19. data/lib/engineyard-serverside/shell/command_result.rb +1 -1
  20. data/lib/engineyard-serverside/strategies/git.rb +14 -4
  21. data/lib/engineyard-serverside/task.rb +1 -0
  22. data/lib/engineyard-serverside/version.rb +1 -1
  23. data/spec/bundler_deploy_spec.rb +36 -33
  24. data/spec/configuration_spec.rb +5 -4
  25. data/spec/custom_deploy_spec.rb +11 -9
  26. data/spec/deploy_hook_spec.rb +10 -3
  27. data/spec/ey_yml_customized_deploy_spec.rb +1 -1
  28. data/spec/fixtures/lockfiles/1.0-no-bundler +1 -1
  29. data/spec/fixtures/lockfiles/1.0.0.rc.1-with-bundler +1 -1
  30. data/spec/fixtures/lockfiles/1.0.18-do_mysql +1 -1
  31. data/spec/fixtures/lockfiles/1.0.18-do_postgres +1 -1
  32. data/spec/fixtures/lockfiles/1.0.18-mysql +1 -1
  33. data/spec/fixtures/lockfiles/1.0.18-mysql2 +1 -1
  34. data/spec/fixtures/lockfiles/1.0.18-pg +1 -1
  35. data/spec/fixtures/lockfiles/1.0.6-no-bundler +2 -2
  36. data/spec/fixtures/lockfiles/1.0.6-with-any-bundler +2 -2
  37. data/spec/fixtures/lockfiles/1.0.6-with-bundler +2 -2
  38. data/spec/fixtures/lockfiles/1.3.1-rails-3.2.13 +112 -0
  39. data/spec/fixtures/repos/{assets_enabled → assets_detected}/Gemfile +1 -2
  40. data/spec/fixtures/repos/{assets_enabled → assets_detected}/Gemfile.lock +1 -3
  41. data/spec/fixtures/repos/{assets_enabled → assets_detected}/README +0 -0
  42. data/spec/fixtures/repos/assets_detected/Rakefile +5 -0
  43. data/spec/fixtures/repos/{assets_enabled → assets_detected}/app/assets/empty +0 -0
  44. data/spec/fixtures/repos/{assets_enabled → assets_detected}/config/application.rb +0 -0
  45. data/spec/fixtures/repos/assets_detected/config/ey.yml +3 -0
  46. data/spec/fixtures/repos/assets_disabled/Gemfile +1 -2
  47. data/spec/fixtures/repos/assets_disabled/Gemfile.lock +1 -3
  48. data/spec/fixtures/repos/assets_disabled/Rakefile +1 -0
  49. data/spec/fixtures/repos/assets_disabled/config/ey.yml +3 -0
  50. data/spec/fixtures/repos/assets_disabled_in_ey_yml/Gemfile +1 -2
  51. data/spec/fixtures/repos/assets_disabled_in_ey_yml/Gemfile.lock +1 -3
  52. data/spec/fixtures/repos/assets_disabled_in_ey_yml/Rakefile +1 -0
  53. data/spec/fixtures/repos/assets_disabled_in_ey_yml/config/ey.yml +1 -0
  54. data/spec/fixtures/repos/assets_enabled_all/Gemfile +1 -2
  55. data/spec/fixtures/repos/assets_enabled_all/Gemfile.lock +1 -3
  56. data/spec/fixtures/repos/assets_enabled_all/Rakefile +1 -0
  57. data/spec/fixtures/repos/assets_enabled_all/config/ey.yml +1 -0
  58. data/spec/fixtures/repos/assets_enabled_in_ey_yml/Gemfile +1 -1
  59. data/spec/fixtures/repos/assets_enabled_in_ey_yml/Gemfile.lock +1 -1
  60. data/spec/fixtures/repos/assets_enabled_in_ey_yml/Rakefile +1 -0
  61. data/spec/fixtures/repos/assets_enabled_util_only/Gemfile +1 -2
  62. data/spec/fixtures/repos/assets_enabled_util_only/Gemfile.lock +1 -3
  63. data/spec/fixtures/repos/assets_enabled_util_only/Rakefile +1 -0
  64. data/spec/fixtures/repos/assets_enabled_util_only/config/ey.yml +1 -0
  65. data/spec/fixtures/repos/assets_in_hook/Gemfile +1 -2
  66. data/spec/fixtures/repos/assets_in_hook/Gemfile.lock +1 -3
  67. data/spec/fixtures/repos/assets_in_hook/config/ey.yml +3 -0
  68. data/spec/fixtures/repos/assets_in_hook/deploy/before_compile_assets.rb +1 -1
  69. data/spec/fixtures/repos/bundle_fails/Gemfile +1 -0
  70. data/spec/fixtures/repos/bundle_fails/README +1 -0
  71. data/spec/fixtures/repos/bundle_fails/deploy/after_bundle.rb +1 -0
  72. data/spec/fixtures/repos/default/Gemfile +1 -2
  73. data/spec/fixtures/repos/default/Gemfile.lock +1 -3
  74. data/spec/fixtures/repos/default/ey.yml +3 -0
  75. data/spec/fixtures/repos/ey_yml/Gemfile +1 -1
  76. data/spec/fixtures/repos/ey_yml/Gemfile.lock +1 -1
  77. data/spec/fixtures/repos/ey_yml/config/ey.yml +11 -7
  78. data/spec/fixtures/repos/ey_yml_alt/Gemfile +1 -1
  79. data/spec/fixtures/repos/ey_yml_alt/Gemfile.lock +1 -1
  80. data/spec/fixtures/repos/no_ey_config/Gemfile +1 -2
  81. data/spec/fixtures/repos/no_ey_config/Gemfile.lock +1 -3
  82. data/spec/fixtures/repos/no_ey_config/ey.yml +3 -0
  83. data/spec/fixtures/repos/no_gemfile_lock/Gemfile +1 -2
  84. data/spec/fixtures/repos/no_gemfile_lock/ey.yml +3 -0
  85. data/spec/fixtures/repos/sqlite3/Gemfile +1 -1
  86. data/spec/fixtures/repos/sqlite3/Gemfile.lock +1 -1
  87. data/spec/lockfile_parser_spec.rb +25 -11
  88. data/spec/rails31_deploy_spec.rb +46 -5
  89. data/spec/restart_spec.rb +3 -3
  90. data/spec/services_deploy_spec.rb +89 -86
  91. data/spec/shell_spec.rb +0 -8
  92. data/spec/spec_helper.rb +81 -36
  93. data/spec/sqlite3_deploy_spec.rb +4 -5
  94. data/spec/support/integration.rb +22 -37
  95. metadata +167 -154
  96. data/lib/engineyard-serverside/lockfile_parser.rb +0 -101
  97. data/lib/engineyard-serverside/rails_asset_support.rb +0 -132
  98. data/spec/fixtures/repos/assets_enabled/Rakefile +0 -5
@@ -22,7 +22,6 @@ require 'engineyard-serverside/task'
22
22
  require 'engineyard-serverside/server'
23
23
  require 'engineyard-serverside/deploy'
24
24
  require 'engineyard-serverside/deploy_hook'
25
- require 'engineyard-serverside/lockfile_parser'
26
25
  require 'engineyard-serverside/cli'
27
26
  require 'engineyard-serverside/configuration'
28
27
  require 'engineyard-serverside/deprecation'
@@ -30,8 +30,9 @@ module EY
30
30
 
31
31
  desc "deploy", "Deploy code from /data/<app>"
32
32
  def deploy(default_task=:deploy)
33
- servers, config, shell = init_and_propagate(options, default_task.to_s)
34
- EY::Serverside::Deploy.new(servers, config, shell).send(default_task)
33
+ init_and_propagate(options, default_task.to_s) do |servers, config, shell|
34
+ EY::Serverside::Deploy.new(servers, config, shell).send(default_task)
35
+ end
35
36
  end
36
37
 
37
38
  account_app_env_options
@@ -40,8 +41,9 @@ module EY
40
41
  verbose_option
41
42
  desc "enable_maintenance", "Enable maintenance page (disables web access)"
42
43
  def enable_maintenance
43
- servers, config, shell = init_and_propagate(options, 'enable_maintenance')
44
- EY::Serverside::Maintenance.new(servers, config, shell).manually_enable
44
+ init_and_propagate(options, 'enable_maintenance') do |servers, config, shell|
45
+ EY::Serverside::Maintenance.new(servers, config, shell).manually_enable
46
+ end
45
47
  end
46
48
 
47
49
  account_app_env_options
@@ -50,8 +52,9 @@ module EY
50
52
  verbose_option
51
53
  desc "disable_maintenance", "Disable maintenance page (enables web access)"
52
54
  def disable_maintenance
53
- servers, config, shell = init_and_propagate(options, 'disable_maintenance')
54
- EY::Serverside::Maintenance.new(servers, config, shell).manually_disable
55
+ init_and_propagate(options, 'disable_maintenance') do |servers, config, shell|
56
+ EY::Serverside::Maintenance.new(servers, config, shell).manually_disable
57
+ end
55
58
  end
56
59
 
57
60
  method_option :release_path, :type => :string,
@@ -69,8 +72,9 @@ module EY
69
72
  verbose_option
70
73
  desc "hook [NAME]", "Run a particular deploy hook"
71
74
  def hook(hook_name)
72
- config, shell = init(options, "hook-#{hook_name}")
73
- EY::Serverside::DeployHook.new(config, shell, hook_name).call
75
+ init(options, "hook-#{hook_name}") do |config, shell|
76
+ EY::Serverside::DeployHook.new(config, shell, hook_name).call
77
+ end
74
78
  end
75
79
 
76
80
  account_app_env_options
@@ -91,22 +95,24 @@ module EY
91
95
  # we have to deploy the same SHA there as here
92
96
  integrate_options[:branch] = current_app_dir.join('REVISION').read.strip
93
97
 
94
- servers, config, shell = init_and_propagate(integrate_options, 'integrate')
98
+ init_and_propagate(integrate_options, 'integrate') do |servers, config, shell|
95
99
 
96
- # We have to rsync the entire app dir, so we need all the permissions to be correct!
97
- shell.logged_system "sudo sh -l -c 'find #{app_dir} -not -user #{config.user} -or -not -group #{config.group} -exec chown #{config.user}:#{config.group} {} +'"
100
+ # We have to rsync the entire app dir, so we need all the permissions to be correct!
101
+ rsync_command = "find #{app_dir} -not -user #{config.user} -or -not -group #{config.group} -exec chown #{config.user}:#{config.group} {} +"
102
+ shell.logged_system "sudo sh -l -c '#{rsync_command}'"
98
103
 
99
- servers.each do |server|
100
- shell.logged_system server.sync_directory_command(app_dir)
101
- # we're just about to recreate this, so it has to be gone
102
- # first. otherwise, non-idempotent deploy hooks could screw
103
- # things up, and since we don't control deploy hooks, we must
104
- # assume the worst.
105
- shell.logged_system server.command_on_server('sh -l -c', "rm -rf #{current_app_dir}")
106
- end
104
+ servers.each do |server|
105
+ shell.logged_system server.sync_directory_command(app_dir)
106
+ # we're just about to recreate this, so it has to be gone
107
+ # first. otherwise, non-idempotent deploy hooks could screw
108
+ # things up, and since we don't control deploy hooks, we must
109
+ # assume the worst.
110
+ shell.logged_system server.command_on_server('sh -l -c', "rm -rf #{current_app_dir}")
111
+ end
107
112
 
108
- # deploy local-ref to other instances into /data/$app/local-current
109
- EY::Serverside::Deploy.new(servers, config, shell).cached_deploy
113
+ # deploy local-ref to other instances into /data/$app/local-current
114
+ EY::Serverside::Deploy.new(servers, config, shell).cached_deploy
115
+ end
110
116
  end
111
117
 
112
118
  account_app_env_options
@@ -115,32 +121,19 @@ module EY
115
121
  verbose_option
116
122
  desc "restart", "Restart app servers, conditionally enabling maintenance page"
117
123
  def restart
118
- servers, config, shell = init_and_propagate(options, 'restart')
119
- EY::Serverside::Deploy.new(servers, config, shell).restart_with_maintenance_page
120
- end
121
-
122
- desc "install_bundler [VERSION]", "Make sure VERSION of bundler is installed (in system ruby)"
123
- def install_bundler(version)
124
- egrep_escaped_version = version.gsub(/\./, '\.')
125
- # the grep "bundler " is so that gems like bundler08 don't get
126
- # their versions considered too
127
- #
128
- # the [,$] is to stop us from looking for e.g. 0.9.2, seeing
129
- # 0.9.22, and mistakenly thinking 0.9.2 is there
130
- has_bundler_cmd = "gem list bundler | grep \"bundler \" | egrep -q '#{egrep_escaped_version}[,)]'"
131
-
132
- unless system(has_bundler_cmd)
133
- system("gem install bundler -q --no-rdoc --no-ri -v '#{version}'")
124
+ init_and_propagate(options, 'restart') do |servers, config, shell|
125
+ EY::Serverside::Deploy.new(servers, config, shell).restart_with_maintenance_page
134
126
  end
135
127
  end
136
128
 
137
129
  private
138
130
 
139
131
  def init_and_propagate(*args)
140
- config, shell = init(*args)
141
- servers = load_servers(config)
142
- Propagator.call(servers, config, shell)
143
- [servers, config, shell]
132
+ init(*args) do |config, shell|
133
+ servers = load_servers(config)
134
+ Propagator.call(servers, config, shell)
135
+ yield servers, config, shell
136
+ end
144
137
  end
145
138
 
146
139
  def init(options, action)
@@ -150,7 +143,15 @@ module EY
150
143
  :log_path => File.join(ENV['HOME'], "#{config.app}-#{action}.log")
151
144
  )
152
145
  shell.debug "Initializing #{About.name_with_version}."
153
- [config, shell]
146
+ begin
147
+ yield config, shell
148
+ rescue EY::Serverside::RemoteFailure => e
149
+ shell.exception "#{e.message}"
150
+ raise
151
+ rescue Exception => e
152
+ shell.exception "#{e.backtrace[0]}: #{e.message} (#{e.class})"
153
+ raise
154
+ end
154
155
  end
155
156
 
156
157
  def load_servers(config)
@@ -166,6 +167,7 @@ module EY
166
167
  }
167
168
  }
168
169
  end
170
+
169
171
  end
170
172
  end
171
173
  end
@@ -1,6 +1,7 @@
1
1
  require 'multi_json'
2
2
  require 'thor'
3
3
  require 'pp'
4
+ require 'yaml'
4
5
  require 'engineyard-serverside/paths'
5
6
 
6
7
  module EY
@@ -56,7 +57,10 @@ module EY
56
57
 
57
58
  def_option :repo, nil
58
59
  def_option :migrate, nil
59
- def_option :precompile_assets, nil
60
+ def_option :precompile_assets, 'detect'
61
+ def_option :precompile_assets_task, 'assets:precompile'
62
+ def_option :asset_strategy, 'shifting'
63
+ def_option :asset_dependencies, %w[app/assets lib/assets vendor/assets Gemfile.lock config/routes.rb]
60
64
  def_option :stack, nil
61
65
  def_option :strategy, 'Git'
62
66
  def_option :branch, 'master'
@@ -64,11 +68,15 @@ module EY
64
68
  def_option :current_name, nil
65
69
  def_option :asset_roles, [:app_master, :app, :solo]
66
70
  def_option :copy_exclude, []
67
- def_option(:bundle_without) { (%w[test development] - [framework_env]).join(' ') }
71
+ def_option :bundle_options, nil
72
+ def_option(:bundle_without) { %w[test development] - [framework_env] }
68
73
  def_option(:user) { ENV['USER'] }
69
74
  def_option(:group) { user }
75
+ def_option :services_check_command, "which /usr/local/ey_resin/ruby/bin/ey-services-setup >/dev/null 2>&1"
76
+ def_option(:services_setup_command) { "/usr/local/ey_resin/ruby/bin/ey-services-setup #{app}" }
70
77
 
71
78
  def_boolean_option :verbose, false
79
+ def_boolean_option :precompile_unchanged_assets, false
72
80
  def_boolean_option :ignore_database_adapter_warning, false
73
81
  def_boolean_option :maintenance_on_migrate, true
74
82
  def_boolean_option(:maintenance_on_restart) { required_downtime_stack? }
@@ -106,6 +114,8 @@ module EY
106
114
  end
107
115
 
108
116
  def load_ey_yml_data(data, shell)
117
+ loaded = false
118
+
109
119
  environments = data['environments']
110
120
  if environments && environments[environment_name]
111
121
  shell.substatus "ey.yml configuration loaded for environment #{environment_name.inspect}."
@@ -113,7 +123,19 @@ module EY
113
123
  env_data = string_keys(environments[environment_name])
114
124
  shell.debug "#{environment_name}:\n#{env_data.pretty_inspect}"
115
125
 
116
- append_config_source(string_keys(env_data)) # insert at lowest priority so as not to disturb important config
126
+ append_config_source(env_data) # insert at higher priority than defaults
127
+ loaded = true
128
+ end
129
+
130
+ defaults = data['defaults']
131
+ if defaults
132
+ shell.substatus "ey.yml configuration loaded."
133
+ append_config_source(string_keys(defaults)) # insert at lowest priority so as not to disturb important config
134
+ shell.debug "defaults:\n#{defaults.pretty_inspect}"
135
+ loaded = true
136
+ end
137
+
138
+ if loaded
117
139
  true
118
140
  else
119
141
  shell.info "No matching ey.yml configuration found for environment #{environment_name.inspect}."
@@ -198,6 +220,22 @@ module EY
198
220
  end
199
221
  alias revision latest_revision
200
222
 
223
+ def previous_revision
224
+ prev = paths.previous_revision
225
+ prev && prev.readable? && prev.read.strip
226
+ end
227
+
228
+ # The nodatabase.yml file is dropped by server configuration when there is
229
+ # no database in the cluster.
230
+ def has_database?
231
+ paths.shared_config.join('database.yml').exist? &&
232
+ !paths.shared_config.join('nodatabase.yml').exist?
233
+ end
234
+
235
+ def check_database_adapter?
236
+ !ignore_database_adapter_warning? && has_database?
237
+ end
238
+
201
239
  def migrate?
202
240
  !!migration_command
203
241
  end
@@ -222,8 +260,15 @@ module EY
222
260
  framework_env_names.each { |e| ENV[e] = environment }
223
261
  end
224
262
 
263
+ def extra_bundle_install_options
264
+ opts = []
265
+ opts += ["--without", bundle_without] if bundle_without
266
+ opts += [bundle_options] if bundle_options
267
+ opts.flatten
268
+ end
269
+
225
270
  def precompile_assets_inferred?
226
- !precompile_assets? && !skip_precompile_assets?
271
+ precompile_assets.nil? || precompile_assets == "detect"
227
272
  end
228
273
 
229
274
  def precompile_assets?
@@ -249,6 +294,12 @@ module EY
249
294
  enable_maintenance_page?
250
295
  end
251
296
 
297
+ def configured_services
298
+ services = YAML.load_file(paths.shared_services_yml.to_s)
299
+ services.respond_to?(:keys) && !services.empty? ? services.keys : nil
300
+ rescue
301
+ nil
302
+ end
252
303
  end
253
304
  end
254
305
  end
@@ -0,0 +1,17 @@
1
+ require 'engineyard-serverside/dependency_manager/base'
2
+ require 'engineyard-serverside/dependency_manager/bundler'
3
+ require 'engineyard-serverside/dependency_manager/bundler_lock'
4
+ require 'engineyard-serverside/dependency_manager/npm'
5
+
6
+ module EY
7
+ module Serverside
8
+ module DependencyManager
9
+ def self.detect(servers, config, shell, runner)
10
+ Bundler.detect(servers, config, shell, runner) ||
11
+ BundlerLock.detect(servers, config, shell, runner) ||
12
+ Npm.detect(servers, config, shell, runner) ||
13
+ Base.new(servers, config, shell, runner)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,65 @@
1
+ module EY
2
+ module Serverside
3
+ module DependencyManager
4
+ class Base
5
+ def self.detect(servers, config, shell, runner)
6
+ manager = new(servers, config, shell, runner)
7
+ manager.detected? && manager
8
+ end
9
+
10
+ attr_reader :servers, :config, :shell, :runner
11
+
12
+ def initialize(servers, config, shell, runner)
13
+ @servers, @config, @shell = servers, config, shell
14
+ @runner = runner
15
+ end
16
+
17
+ # Public interface
18
+ #
19
+
20
+ def detected?() true end
21
+ def check() end
22
+ def install() end
23
+
24
+ # assume not using sqlite3 unless a dependency system says so
25
+ def uses_sqlite3?() false end
26
+ def rails_version() end
27
+ def check_ey_config() end
28
+
29
+ # Legacy methods, this should not be public API to this class
30
+ # With proper warning, cut these methods off
31
+ def gemfile?() end
32
+ def bundler_config
33
+ raise "This method has been removed. Use bundle_options in ey.yml"
34
+ end
35
+ def lockfile() end
36
+ def check_ruby_bundler() end
37
+ def check_node_npm() end
38
+ def clean_bundle_on_system_version_change() end
39
+ def write_system_version() end
40
+
41
+ protected
42
+
43
+ def paths
44
+ config.paths
45
+ end
46
+
47
+ def on_roles
48
+ [:app_master, :app, :solo, :util]
49
+ end
50
+
51
+ def run(cmd)
52
+ runner.roles(on_roles) do
53
+ runner.run(cmd)
54
+ end
55
+ end
56
+
57
+ def sudo(cmd)
58
+ runner.roles(on_roles) do
59
+ runner.sudo(cmd)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,124 @@
1
+ module EY
2
+ module Serverside
3
+ module DependencyManager
4
+ class Bundler < Base
5
+ DEFAULT_VERSION = "1.3.4"
6
+
7
+ def self.default_version
8
+ DEFAULT_VERSION
9
+ end
10
+
11
+ def detected?
12
+ gemfile? && !lockfile?
13
+ end
14
+
15
+ def gemfile?
16
+ paths.gemfile.exist?
17
+ end
18
+
19
+ def lockfile?
20
+ lockfile_path.exist?
21
+ end
22
+
23
+ def check
24
+ shell.warning <<-WARN
25
+ Gemfile found but Gemfile.lock is missing!
26
+ You can get different versions of gems in production than what you tested with.
27
+ You can get different versions of gems on every deployment even if your Gemfile hasn't changed.
28
+ Deploying will take longer and some deploy options will be limited.
29
+
30
+ To fix this problem, commit your Gemfile.lock to your repository and redeploy.
31
+ WARN
32
+ end
33
+
34
+ def install
35
+ check_ruby_bundler
36
+ end
37
+
38
+ # Without Gemfile.lock, don't do anything with sqlite3
39
+ def uses_sqlite3?
40
+ false
41
+ end
42
+
43
+ # Without Gemfile.lock, don't do anything about ey_config
44
+ def check_ey_config
45
+ end
46
+
47
+ # Without Gemfile.lock, there is no determining the rails version.
48
+ def rails_version
49
+ nil
50
+ end
51
+
52
+ private
53
+
54
+ def lockfile_path
55
+ paths.gemfile_lock
56
+ end
57
+
58
+ def write_system_version
59
+ store_ruby_version = "#{config.ruby_version_command} > #{paths.ruby_version}"
60
+ store_system_version = "#{config.system_version_command} > #{paths.system_version}"
61
+
62
+ run "mkdir -p #{paths.bundled_gems} && chown #{config.user}:#{config.group} #{paths.bundled_gems}"
63
+ run "#{store_ruby_version} && #{store_system_version}"
64
+ end
65
+
66
+ def check_ruby_bundler
67
+ shell.status "Bundling gems..."
68
+ clean_bundle_on_system_version_change
69
+ install_bundler_gem
70
+ run "#{clean_environment} && cd #{paths.active_release} && #{bundle_install_command}"
71
+ write_system_version
72
+ end
73
+
74
+ # Install bundler in the system ruby
75
+ def install_bundler_gem
76
+ egrep_escaped_version = bundler_version.gsub(/\./, '\.')
77
+ # the grep "bundler " is so that gems like bundler08 don't get
78
+ # their versions considered too
79
+ #
80
+ # the [,)] is to stop us from looking for e.g. 0.9.2, seeing
81
+ # 0.9.22, and mistakenly thinking 0.9.2 is there
82
+ clean_ruby = %{unset RUBYOPT}
83
+ has_gem_cmd = %{gem list bundler | grep "bundler " | egrep -q "#{egrep_escaped_version}[,)]"}
84
+ install_cmd = %{gem install bundler -q --no-rdoc --no-ri -v "#{bundler_version}"}
85
+ sudo "#{clean_ruby} && #{has_gem_cmd} || #{install_cmd}"
86
+ end
87
+
88
+ # GIT_SSH needs to be defined in the environment for customers with private bundler repos in their Gemfile.
89
+ # It seems redundant to declare the env var again, but I'm hesitant to remove it right now.
90
+ def clean_environment
91
+ %{export GIT_SSH="#{ENV['GIT_SSH']}" && export LANG="en_US.UTF-8" && unset RUBYOPT BUNDLE_PATH BUNDLE_FROZEN BUNDLE_WITHOUT BUNDLE_BIN BUNDLE_GEMFILE}
92
+ end
93
+
94
+ def bundle_install_options
95
+ options = [
96
+ "--gemfile", "#{paths.gemfile}",
97
+ "--path", "#{paths.bundled_gems}",
98
+ "--binstubs", "#{paths.binstubs}",
99
+ ]
100
+ options += config.extra_bundle_install_options
101
+ options
102
+ end
103
+
104
+ def bundle_install_command
105
+ "ruby -S bundle _#{bundler_version}_ install #{bundle_install_options.join(" ")}"
106
+ end
107
+
108
+ def clean_bundle_on_system_version_change
109
+ # diff exits with 0 for same and 1/2 for different/file not found.
110
+ check_ruby = "#{config.ruby_version_command} | diff - #{paths.ruby_version} >/dev/null 2>&1"
111
+ check_system = "#{config.system_version_command} | diff - #{paths.system_version} >/dev/null 2>&1"
112
+ clean_bundle = "rm -Rf #{paths.bundled_gems}"
113
+
114
+ shell.substatus "Checking for system version changes"
115
+ run "#{check_ruby} && #{check_system} || #{clean_bundle}"
116
+ end
117
+
118
+ def bundler_version
119
+ self.class.default_version
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end