engineyard-serverside 2.0.7 → 2.1.0.pre
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.
- data/lib/engineyard-serverside.rb +0 -1
- data/lib/engineyard-serverside/cli.rb +44 -42
- data/lib/engineyard-serverside/configuration.rb +55 -4
- data/lib/engineyard-serverside/dependency_manager.rb +17 -0
- data/lib/engineyard-serverside/dependency_manager/base.rb +65 -0
- data/lib/engineyard-serverside/dependency_manager/bundler.rb +124 -0
- data/lib/engineyard-serverside/dependency_manager/bundler_lock.rb +155 -0
- data/lib/engineyard-serverside/dependency_manager/legacy_helpers.rb +24 -0
- data/lib/engineyard-serverside/dependency_manager/npm.rb +16 -0
- data/lib/engineyard-serverside/deploy.rb +86 -178
- data/lib/engineyard-serverside/deprecation.rb +11 -1
- data/lib/engineyard-serverside/paths.rb +6 -0
- data/lib/engineyard-serverside/propagator.rb +2 -2
- data/lib/engineyard-serverside/rails_assets.rb +152 -0
- data/lib/engineyard-serverside/rails_assets/strategy.rb +197 -0
- data/lib/engineyard-serverside/server.rb +5 -0
- data/lib/engineyard-serverside/servers.rb +19 -7
- data/lib/engineyard-serverside/shell.rb +7 -5
- data/lib/engineyard-serverside/shell/command_result.rb +1 -1
- data/lib/engineyard-serverside/strategies/git.rb +14 -4
- data/lib/engineyard-serverside/task.rb +1 -0
- data/lib/engineyard-serverside/version.rb +1 -1
- data/spec/bundler_deploy_spec.rb +36 -33
- data/spec/configuration_spec.rb +5 -4
- data/spec/custom_deploy_spec.rb +11 -9
- data/spec/deploy_hook_spec.rb +10 -3
- data/spec/ey_yml_customized_deploy_spec.rb +1 -1
- data/spec/fixtures/lockfiles/1.0-no-bundler +1 -1
- data/spec/fixtures/lockfiles/1.0.0.rc.1-with-bundler +1 -1
- data/spec/fixtures/lockfiles/1.0.18-do_mysql +1 -1
- data/spec/fixtures/lockfiles/1.0.18-do_postgres +1 -1
- data/spec/fixtures/lockfiles/1.0.18-mysql +1 -1
- data/spec/fixtures/lockfiles/1.0.18-mysql2 +1 -1
- data/spec/fixtures/lockfiles/1.0.18-pg +1 -1
- data/spec/fixtures/lockfiles/1.0.6-no-bundler +2 -2
- data/spec/fixtures/lockfiles/1.0.6-with-any-bundler +2 -2
- data/spec/fixtures/lockfiles/1.0.6-with-bundler +2 -2
- data/spec/fixtures/lockfiles/1.3.1-rails-3.2.13 +112 -0
- data/spec/fixtures/repos/{assets_enabled → assets_detected}/Gemfile +1 -2
- data/spec/fixtures/repos/{assets_enabled → assets_detected}/Gemfile.lock +1 -3
- data/spec/fixtures/repos/{assets_enabled → assets_detected}/README +0 -0
- data/spec/fixtures/repos/assets_detected/Rakefile +5 -0
- data/spec/fixtures/repos/{assets_enabled → assets_detected}/app/assets/empty +0 -0
- data/spec/fixtures/repos/{assets_enabled → assets_detected}/config/application.rb +0 -0
- data/spec/fixtures/repos/assets_detected/config/ey.yml +3 -0
- data/spec/fixtures/repos/assets_disabled/Gemfile +1 -2
- data/spec/fixtures/repos/assets_disabled/Gemfile.lock +1 -3
- data/spec/fixtures/repos/assets_disabled/Rakefile +1 -0
- data/spec/fixtures/repos/assets_disabled/config/ey.yml +3 -0
- data/spec/fixtures/repos/assets_disabled_in_ey_yml/Gemfile +1 -2
- data/spec/fixtures/repos/assets_disabled_in_ey_yml/Gemfile.lock +1 -3
- data/spec/fixtures/repos/assets_disabled_in_ey_yml/Rakefile +1 -0
- data/spec/fixtures/repos/assets_disabled_in_ey_yml/config/ey.yml +1 -0
- data/spec/fixtures/repos/assets_enabled_all/Gemfile +1 -2
- data/spec/fixtures/repos/assets_enabled_all/Gemfile.lock +1 -3
- data/spec/fixtures/repos/assets_enabled_all/Rakefile +1 -0
- data/spec/fixtures/repos/assets_enabled_all/config/ey.yml +1 -0
- data/spec/fixtures/repos/assets_enabled_in_ey_yml/Gemfile +1 -1
- data/spec/fixtures/repos/assets_enabled_in_ey_yml/Gemfile.lock +1 -1
- data/spec/fixtures/repos/assets_enabled_in_ey_yml/Rakefile +1 -0
- data/spec/fixtures/repos/assets_enabled_util_only/Gemfile +1 -2
- data/spec/fixtures/repos/assets_enabled_util_only/Gemfile.lock +1 -3
- data/spec/fixtures/repos/assets_enabled_util_only/Rakefile +1 -0
- data/spec/fixtures/repos/assets_enabled_util_only/config/ey.yml +1 -0
- data/spec/fixtures/repos/assets_in_hook/Gemfile +1 -2
- data/spec/fixtures/repos/assets_in_hook/Gemfile.lock +1 -3
- data/spec/fixtures/repos/assets_in_hook/config/ey.yml +3 -0
- data/spec/fixtures/repos/assets_in_hook/deploy/before_compile_assets.rb +1 -1
- data/spec/fixtures/repos/bundle_fails/Gemfile +1 -0
- data/spec/fixtures/repos/bundle_fails/README +1 -0
- data/spec/fixtures/repos/bundle_fails/deploy/after_bundle.rb +1 -0
- data/spec/fixtures/repos/default/Gemfile +1 -2
- data/spec/fixtures/repos/default/Gemfile.lock +1 -3
- data/spec/fixtures/repos/default/ey.yml +3 -0
- data/spec/fixtures/repos/ey_yml/Gemfile +1 -1
- data/spec/fixtures/repos/ey_yml/Gemfile.lock +1 -1
- data/spec/fixtures/repos/ey_yml/config/ey.yml +11 -7
- data/spec/fixtures/repos/ey_yml_alt/Gemfile +1 -1
- data/spec/fixtures/repos/ey_yml_alt/Gemfile.lock +1 -1
- data/spec/fixtures/repos/no_ey_config/Gemfile +1 -2
- data/spec/fixtures/repos/no_ey_config/Gemfile.lock +1 -3
- data/spec/fixtures/repos/no_ey_config/ey.yml +3 -0
- data/spec/fixtures/repos/no_gemfile_lock/Gemfile +1 -2
- data/spec/fixtures/repos/no_gemfile_lock/ey.yml +3 -0
- data/spec/fixtures/repos/sqlite3/Gemfile +1 -1
- data/spec/fixtures/repos/sqlite3/Gemfile.lock +1 -1
- data/spec/lockfile_parser_spec.rb +25 -11
- data/spec/rails31_deploy_spec.rb +46 -5
- data/spec/restart_spec.rb +3 -3
- data/spec/services_deploy_spec.rb +89 -86
- data/spec/shell_spec.rb +0 -8
- data/spec/spec_helper.rb +81 -36
- data/spec/sqlite3_deploy_spec.rb +4 -5
- data/spec/support/integration.rb +22 -37
- metadata +167 -154
- data/lib/engineyard-serverside/lockfile_parser.rb +0 -101
- data/lib/engineyard-serverside/rails_asset_support.rb +0 -132
- data/spec/fixtures/repos/assets_enabled/Rakefile +0 -5
|
@@ -6,10 +6,20 @@ module EY
|
|
|
6
6
|
$stderr.puts "DEPRECATION WARNING: #{msg}\n\t#{caller(2).first}"
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
+
def self.deprecated_task(receiver, old_task, new_task)
|
|
10
|
+
if receiver.respond_to?(old_task)
|
|
11
|
+
deprecation_warning("Task ##{old_task} has been renamed to ##{new_task}.")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
9
15
|
def self.const_missing(const)
|
|
10
|
-
|
|
16
|
+
case const
|
|
17
|
+
when :LoggedOutput
|
|
11
18
|
EY::Serverside.deprecation_warning("EY::Serverside::LoggedOutput has been deprecated. Use EY::Serverside::Shell::Helpers instead.")
|
|
12
19
|
EY::Serverside::Shell::Helpers
|
|
20
|
+
when :LockfileParser
|
|
21
|
+
EY::Serverside.deprecation_warning("EY::Serverside::LockfileParser has been deprecated. Use EY::Serverside::DependencyManager::BundlerLock::Lockfile instead.")
|
|
22
|
+
EY::Serverside::DependencyManager::BundlerLock::Lockfile
|
|
13
23
|
else
|
|
14
24
|
super
|
|
15
25
|
end
|
|
@@ -70,6 +70,7 @@ module EY
|
|
|
70
70
|
def_path :enabled_maintenance_page, [:shared_system, 'maintenance.html']
|
|
71
71
|
def_path :shared_assets, [:shared, 'assets']
|
|
72
72
|
def_path :bundled_gems, [:shared, 'bundled_gems']
|
|
73
|
+
def_path :shared_services_yml, [:shared_config, 'ey_services_config_deploy.yml']
|
|
73
74
|
def_path :ruby_version, [:bundled_gems, 'RUBY_VERSION']
|
|
74
75
|
def_path :system_version, [:bundled_gems, 'SYSTEM_VERSION']
|
|
75
76
|
def_path :latest_revision, [:latest_release, 'REVISION']
|
|
@@ -127,6 +128,11 @@ module EY
|
|
|
127
128
|
end
|
|
128
129
|
end
|
|
129
130
|
|
|
131
|
+
def previous_revision
|
|
132
|
+
rel = previous_release(active_release)
|
|
133
|
+
rel && rel.join('REVISION')
|
|
134
|
+
end
|
|
135
|
+
|
|
130
136
|
# deploy_root/releases/<latest timestamp>
|
|
131
137
|
def latest_release
|
|
132
138
|
all_releases.last
|
|
@@ -67,8 +67,8 @@ module EY
|
|
|
67
67
|
|
|
68
68
|
def propagate
|
|
69
69
|
shell.status "Propagating #{About.name_with_version} to #{count_servers(servers)}."
|
|
70
|
-
servers.run_on_each { |server| shell.logged_system(scp_command(server)) }
|
|
71
|
-
servers.run_on_each { |server| shell.logged_system(server.command_on_server('sudo sh -l -c', install_command)) }
|
|
70
|
+
servers.run_on_each(shell) { |server| shell.logged_system(scp_command(server)) }
|
|
71
|
+
servers.run_on_each(shell) { |server| shell.logged_system(server.command_on_server('sudo sh -l -c', install_command)) }
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
require 'engineyard-serverside/rails_assets/strategy'
|
|
2
|
+
require 'forwardable'
|
|
3
|
+
|
|
4
|
+
module EY
|
|
5
|
+
module Serverside
|
|
6
|
+
class RailsAssets
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
def self.detect_and_compile(*args)
|
|
10
|
+
new(*args).detect_and_compile
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_reader :config, :shell, :runner
|
|
14
|
+
|
|
15
|
+
def initialize(config, shell, runner)
|
|
16
|
+
@config, @shell, @runner = config, shell, runner
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def_delegators :config,
|
|
20
|
+
:paths, :asset_dependencies, :asset_roles,
|
|
21
|
+
:framework_envs, :precompile_assets?, :skip_precompile_assets?,
|
|
22
|
+
:precompile_unchanged_assets?, :precompile_assets_task
|
|
23
|
+
|
|
24
|
+
def detect_and_compile
|
|
25
|
+
runner.roles asset_roles do
|
|
26
|
+
if precompile_assets?
|
|
27
|
+
if precompile_unchanged_assets?
|
|
28
|
+
shell.status "Precompiling assets without change detection. (precompile_unchanged_assets: true)"
|
|
29
|
+
run_precompile_assets_task
|
|
30
|
+
elsif reuse_assets?
|
|
31
|
+
shell.status "Reusing existing assets. (configured asset_dependencies unchanged from #{previous_revision[0,7]}..#{active_revision[0,7]})"
|
|
32
|
+
asset_strategy.reuse
|
|
33
|
+
else
|
|
34
|
+
shell.status "Precompiling assets. (precompile_assets: true)"
|
|
35
|
+
run_precompile_assets_task
|
|
36
|
+
end
|
|
37
|
+
elsif skip_precompile_assets?
|
|
38
|
+
shell.status "Skipping asset precompilation. (precompile_assets: false)"
|
|
39
|
+
elsif !application_rb_path.readable? || !app_assets_path.directory?
|
|
40
|
+
# Not a Rails app. Ignore assets completely.
|
|
41
|
+
elsif app_disables_assets?
|
|
42
|
+
shell.status "Skipping asset precompilation. ('config/application.rb' disables assets.)"
|
|
43
|
+
elsif paths.public_assets.exist?
|
|
44
|
+
shell.status "Skipping asset precompilation. ('public/assets' directory already exists.)"
|
|
45
|
+
else
|
|
46
|
+
precompile_detected_assets
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def run_precompile_assets_task
|
|
52
|
+
asset_strategy.prepare do
|
|
53
|
+
cd = "cd #{paths.active_release}"
|
|
54
|
+
task = "PATH=#{paths.binstubs}:$PATH #{framework_envs} rake #{precompile_assets_task} RAILS_GROUPS=assets"
|
|
55
|
+
runner.run "#{cd} && #{task}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def previous_revision
|
|
60
|
+
@previous_revision ||= config.previous_revision
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def active_revision
|
|
64
|
+
@active_revision ||= config.active_revision
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Note on reusing assets when assets may fail silently:
|
|
68
|
+
# It's difficult and error prone to reuse assets that may have failed
|
|
69
|
+
# silently in the previous deploy. If the assets are unchanged during
|
|
70
|
+
# this deploy, but failed last deploy, we would incorrectly reuse
|
|
71
|
+
# silentely failed assets. Only reusing when assets are enabled
|
|
72
|
+
# ensures that existing assets were successful.
|
|
73
|
+
def reuse_assets?
|
|
74
|
+
previous_revision &&
|
|
75
|
+
active_revision &&
|
|
76
|
+
runner.strategy.same?(previous_revision, active_revision, asset_dependencies)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def precompile_detected_assets
|
|
80
|
+
shell.status "Precompiling assets. ('#{app_assets}' exists, 'public/assets' not found, not disabled in config.)"
|
|
81
|
+
if !runner.dependency_manager.rails_version
|
|
82
|
+
shell.warning "Precompiling assets even though Rails was not bundled."
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
run_precompile_assets_task
|
|
86
|
+
|
|
87
|
+
shell.warning <<-WARN
|
|
88
|
+
Inferred asset compilation succeeded, but failures may be silently ignored!
|
|
89
|
+
|
|
90
|
+
ACTION REQUIRED: Add precompile_assets option to ey.yml.
|
|
91
|
+
precompile_assets: true # precompile assets when asset changes detected
|
|
92
|
+
WARN
|
|
93
|
+
rescue EY::Serverside::RemoteFailure => e
|
|
94
|
+
# If we are implicitly precompiling, we want to fail non-destructively
|
|
95
|
+
# because we don't know if the rake task exists or if the user
|
|
96
|
+
# actually intended for assets to be compiled.
|
|
97
|
+
if e.to_s =~ /Don't know how to build task '#{precompile_assets_task}'/
|
|
98
|
+
shell.warning <<-WARN
|
|
99
|
+
Asset precompilation detected but compilation failure ignored!
|
|
100
|
+
Rake task '#{precompile_assets_task}' was not found.
|
|
101
|
+
|
|
102
|
+
ACTION REQUIRED: Add precompile_assets option to ey.yml.
|
|
103
|
+
precompile_assets: false # disable assets to avoid this error.
|
|
104
|
+
WARN
|
|
105
|
+
else
|
|
106
|
+
shell.error <<-ERROR
|
|
107
|
+
Asset precompilation detected but compilation failed!
|
|
108
|
+
|
|
109
|
+
ACTION REQUIRED: Add precompile_assets option to ey.yml.
|
|
110
|
+
precompile_assets: true # precompile assets when asset changes detected
|
|
111
|
+
precompile_assets: false # disable asset compilation.
|
|
112
|
+
ERROR
|
|
113
|
+
raise
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def app_disables_assets?
|
|
118
|
+
application_rb_path.open do |fd|
|
|
119
|
+
fd.grep(/^[^#]*config\.assets\.enabled\s*=\s*(false|nil)/).any?
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# This check is very expensive, and has been deemed not worth the time.
|
|
124
|
+
# Leaving this here in case someone comes up with a faster way.
|
|
125
|
+
#
|
|
126
|
+
# Runs 'rake -T' to see if there is an assets:precompile task.
|
|
127
|
+
def app_has_asset_task?
|
|
128
|
+
# We just run this locally on the app master; everybody else should
|
|
129
|
+
# have the same code anyway.
|
|
130
|
+
task_check = "PATH=#{paths.binstubs}:$PATH #{framework_envs} rake -T #{precompile_assets_task} | grep '#{precompile_assets_task}'"
|
|
131
|
+
cmd = "cd #{paths.active_release} && #{task_check}"
|
|
132
|
+
shell.logged_system(cmd).success?
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def application_rb_path
|
|
136
|
+
paths.active_release.join('config','application.rb')
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def app_assets
|
|
140
|
+
File.join('app','assets')
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def app_assets_path
|
|
144
|
+
paths.active_release.join(app_assets)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def asset_strategy
|
|
148
|
+
@asset_strategy ||= RailsAssets::Strategy.fetch(config.asset_strategy, paths, runner)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
module EY
|
|
4
|
+
module Serverside
|
|
5
|
+
class RailsAssets
|
|
6
|
+
module Strategy
|
|
7
|
+
def self.all
|
|
8
|
+
{
|
|
9
|
+
'shared' => Shared,
|
|
10
|
+
'cleaning' => Cleaning,
|
|
11
|
+
'private' => Private,
|
|
12
|
+
'shifting' => Shifting,
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.fetch(name, *args)
|
|
17
|
+
(all[name.to_s] || Shifting).new(*args)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Precompile assets fresh every time. Shared assets are not symlinked
|
|
22
|
+
# and assets stay with the release that compiled them. The assets of
|
|
23
|
+
# the previous deploy are symlinked as into the current deploy to
|
|
24
|
+
# prevent errors during deploy.
|
|
25
|
+
#
|
|
26
|
+
# When no assets changes are detected, the deploy uses rsync to copy
|
|
27
|
+
# the previous release's assets into the current assets directory.
|
|
28
|
+
class Private
|
|
29
|
+
attr_reader :paths, :runner
|
|
30
|
+
|
|
31
|
+
def initialize(paths, runner)
|
|
32
|
+
@paths = paths
|
|
33
|
+
@runner = runner
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def reuse
|
|
37
|
+
run("mkdir -p #{paths.public_assets} && rsync -aq #{previous_assets_path}/ #{paths.public_assets}")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# ?ink the previous assets into the new public/last_assets/assets
|
|
41
|
+
# to prevent missing assets during deploy.
|
|
42
|
+
#
|
|
43
|
+
# This results in the directory structure:
|
|
44
|
+
# deploy_root/current/public/last_assets/assets -> deploy_root/releases/<prev>/public/assets
|
|
45
|
+
def prepare
|
|
46
|
+
last = paths.public.join('last_assets')
|
|
47
|
+
run "mkdir -p #{last} && ln -nfs #{previous_assets_path} #{last.join('assets')}"
|
|
48
|
+
yield
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
protected
|
|
52
|
+
|
|
53
|
+
def run(cmd)
|
|
54
|
+
runner.run(cmd)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def previous_assets_path
|
|
58
|
+
paths.previous_release(paths.active_release).join('public','assets')
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Basic shared assets.
|
|
63
|
+
# Precompiled assets go into a single shared assets directory. The
|
|
64
|
+
# assets directory is never cleaned, so a deploy hook should be used
|
|
65
|
+
# to clean assets appropriately.
|
|
66
|
+
#
|
|
67
|
+
# When no assets changes are detected, shared directory is only
|
|
68
|
+
# symlinked and precompile task is not run.
|
|
69
|
+
class Shared
|
|
70
|
+
attr_reader :paths, :runner
|
|
71
|
+
def initialize(paths, runner)
|
|
72
|
+
@paths = paths
|
|
73
|
+
@runner = runner
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def reuse
|
|
77
|
+
run "mkdir -p #{shared_assets_path} && ln -nfs #{shared_assets_path} #{paths.public}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def prepare
|
|
81
|
+
reuse
|
|
82
|
+
yield
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
protected
|
|
86
|
+
|
|
87
|
+
def run(cmd)
|
|
88
|
+
runner.run(cmd)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def shared_assets_path
|
|
92
|
+
paths.shared_assets
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Precompiled assets are shared across all deploys like Shared.
|
|
97
|
+
# Before compiling the active deploying assets, all assets that are not
|
|
98
|
+
# referenced by the manifest.yml from the previous deploy are removed.
|
|
99
|
+
# After cleaning, the new assets are compiled over the top. The result
|
|
100
|
+
# is an assets dir that contains the last assets and the current assets.
|
|
101
|
+
#
|
|
102
|
+
# When no assets changes are detected, shared directory is only
|
|
103
|
+
# symlinked and cleaning and precompile tasks are not run.
|
|
104
|
+
class Cleaning < Shared
|
|
105
|
+
def prepare
|
|
106
|
+
reuse
|
|
107
|
+
remove_old_assets
|
|
108
|
+
yield
|
|
109
|
+
rescue
|
|
110
|
+
# how do you restore back to the old assets if some have been overwritten?
|
|
111
|
+
# probably just deploy again I suppose.
|
|
112
|
+
raise
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
protected
|
|
116
|
+
|
|
117
|
+
def remove_old_assets
|
|
118
|
+
return unless manifest_path.readable?
|
|
119
|
+
|
|
120
|
+
Dir.chdir(shared_assets_path)
|
|
121
|
+
|
|
122
|
+
all_assets_on_disk = Dir.glob(shared_assets_path.join('**','*.*').to_s) - [manifest_path.to_s]
|
|
123
|
+
$stderr.puts "all_assets_on_disk #{all_assets_on_disk.inspect}"
|
|
124
|
+
assets_on_disk = all_assets_on_disk.reject {|a| a =~ /\.gz$/}
|
|
125
|
+
$stderr.puts "assets_on_disk #{assets_on_disk.inspect}"
|
|
126
|
+
assets_in_manifest = YAML.load_file(manifest_path.to_s).values
|
|
127
|
+
$stderr.puts "assets_in_manifest #{assets_in_manifest.inspect}"
|
|
128
|
+
|
|
129
|
+
remove_assets = []
|
|
130
|
+
(assets_on_disk - assets_in_manifest).each do |asset|
|
|
131
|
+
remove_assets << "'#{asset}'"
|
|
132
|
+
remove_assets << "'#{asset}.gz'" if all_assets_on_disk.include?("#{asset}.gz")
|
|
133
|
+
end
|
|
134
|
+
run("rm -rf #{remove_assets.join(' ')}")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def manifest_path
|
|
138
|
+
shared_assets_path.join('manifest.yml')
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# The default behavior and the one used since the beginning of asset
|
|
143
|
+
# support in engineyard-serverside. Assets are compiled into a fresh
|
|
144
|
+
# shared directory. Previous shared assets are shifted to a last_assets
|
|
145
|
+
# directory to prevent errors during deploy.
|
|
146
|
+
#
|
|
147
|
+
# When no assets changes are detected, the two shared directories are
|
|
148
|
+
# symlinked into the active release without any changes.
|
|
149
|
+
class Shifting < Shared
|
|
150
|
+
# link shared/assets and shared/last_assets into public
|
|
151
|
+
def reuse
|
|
152
|
+
run "mkdir -p #{shared_assets_path} #{last_assets_path} && #{link_assets}"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def prepare
|
|
156
|
+
shift_existing_assets
|
|
157
|
+
yield
|
|
158
|
+
rescue
|
|
159
|
+
unshift_existing_assets
|
|
160
|
+
raise
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
protected
|
|
164
|
+
|
|
165
|
+
def last_assets_path
|
|
166
|
+
paths.shared.join('last_assets')
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# If there are current shared assets, move them under a 'last_assets' directory.
|
|
170
|
+
#
|
|
171
|
+
# To support operations like Unicorn's hot reload, it is useful to have
|
|
172
|
+
# the prior release's assets as well. Otherwise, while a deploy is running,
|
|
173
|
+
# clients may request stale assets that you just deleted.
|
|
174
|
+
# Making use of this requires a properly-configured front-end HTTP server.
|
|
175
|
+
#
|
|
176
|
+
# Note: This results in the directory structure:
|
|
177
|
+
# deploy_root/current/public/assets -> deploy_root/shared/assets
|
|
178
|
+
# deploy_root/current/public/last_assets -> deploy_root/shared/last_assets
|
|
179
|
+
# where last_assets has an assets dir under it.
|
|
180
|
+
# deploy_root/shared/last_assets/assets
|
|
181
|
+
def shift_existing_assets
|
|
182
|
+
run "rm -rf #{last_assets_path} && mkdir -p #{shared_assets_path} #{last_assets_path} && mv #{shared_assets_path} #{last_assets_path.join('assets')} && mkdir -p #{shared_assets_path} && #{link_assets}"
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Restore shared/last_assets to shared/assets and relink them to the app public
|
|
186
|
+
def unshift_existing_assets
|
|
187
|
+
run "rm -rf #{shared_assets_path} && mv #{last_assets_path.join('assets')} #{shared_assets_path} && mkdir -p #{last_assets_path} && #{link_assets}"
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def link_assets
|
|
191
|
+
"ln -nfs #{shared_assets_path} #{last_assets_path} #{paths.public}"
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
@@ -64,17 +64,17 @@ module EY
|
|
|
64
64
|
|
|
65
65
|
# Run a command on this set of servers.
|
|
66
66
|
def run(shell, cmd, &block)
|
|
67
|
-
run_on_each do |server|
|
|
67
|
+
run_on_each(shell) do |server|
|
|
68
68
|
exec_cmd = server.command_on_server('sh -l -c', cmd, &block)
|
|
69
|
-
shell.logged_system(exec_cmd)
|
|
69
|
+
shell.logged_system(exec_cmd, server)
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
# Run a sudo command on this set of servers.
|
|
74
74
|
def sudo(shell, cmd, &block)
|
|
75
|
-
run_on_each do |server|
|
|
75
|
+
run_on_each(shell) do |server|
|
|
76
76
|
exec_cmd = server.command_on_server('sudo sh -l -c', cmd, &block)
|
|
77
|
-
shell.logged_system(exec_cmd)
|
|
77
|
+
shell.logged_system(exec_cmd, server)
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
|
|
@@ -93,12 +93,24 @@ module EY
|
|
|
93
93
|
# Makes a theard for each server and executes the block,
|
|
94
94
|
# Assumes that the return value of the block is a CommandResult
|
|
95
95
|
# and ensures that all the command results were successful.
|
|
96
|
-
def run_on_each(&block)
|
|
96
|
+
def run_on_each(shell, &block)
|
|
97
97
|
results = map_in_parallel(&block)
|
|
98
98
|
failures = results.reject {|result| result.success? }
|
|
99
|
+
|
|
99
100
|
if failures.any?
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
commands = failures.map { |f| f.command }.uniq
|
|
102
|
+
servers = failures.map { |f| f.server }.compact.map { |s| s.inspect }
|
|
103
|
+
outputs = failures.map { |f| f.output }.uniq
|
|
104
|
+
message = "The following command#{commands.size == 1 ? '' : 's'} failed"
|
|
105
|
+
if servers.any?
|
|
106
|
+
message << " on server#{servers.size == 1 ? '' : 's'} [#{servers.join(', ')}]"
|
|
107
|
+
end
|
|
108
|
+
message << "\n\n"
|
|
109
|
+
commands.each do |cmd|
|
|
110
|
+
message << "$ #{cmd}\n"
|
|
111
|
+
end
|
|
112
|
+
message << "\n" << outputs.join("\n\n") << "\n"
|
|
113
|
+
raise EY::Serverside::RemoteFailure.new(message)
|
|
102
114
|
end
|
|
103
115
|
end
|
|
104
116
|
|