Permalink
Browse files

[SS-12] [SS-24] Compile and symlink assets for Rails 3.1 apps as needed.

  • Loading branch information...
1 parent e91b182 commit f770496f5e14579c889e4d345f77d606de551de2 @wilson wilson committed Sep 27, 2011
@@ -132,6 +132,10 @@ def restart_command
"/engineyard/bin/app_#{c.app} deploy"
end
+ def clean_environment
+ "env -i PATH=$PATH HOME=$HOME GEM_PATH=$GEM_PATH GEM_HOME=$GEM_HOME"
+ end
+
# task
def bundle
if File.exist?("#{c.release_path}/Gemfile")
@@ -145,7 +149,7 @@ def bundle
get_default_bundler_installer
end
- sudo "#{serverside_bin} install_bundler #{bundler_installer.version}"
+ sudo "#{clean_environment} #{serverside_bin} install_bundler #{bundler_installer.version}"
bundled_gems_path = File.join(c.shared_path, "bundled_gems")
ruby_version_file = File.join(bundled_gems_path, "RUBY_VERSION")
@@ -165,7 +169,7 @@ def bundle
end
end
- run "cd #{c.release_path} && ruby -S bundle _#{bundler_installer.version}_ install #{bundler_installer.options}"
+ run "cd #{c.release_path} && #{clean_environment} ruby -S bundle _#{bundler_installer.version}_ install #{bundler_installer.options}"
run "mkdir -p #{bundled_gems_path} && ruby -v > #{ruby_version_file} && uname -m > #{system_version_file}"
end
@@ -224,24 +228,31 @@ def create_revision_file
end
def symlink_configs(release_to_link=c.release_path)
- info "~> Symlinking configs"
- [ "chmod -R g+w #{release_to_link}",
- "rm -rf #{release_to_link}/log #{release_to_link}/public/system #{release_to_link}/tmp/pids",
- "mkdir -p #{release_to_link}/tmp",
- "ln -nfs #{c.shared_path}/log #{release_to_link}/log",
- "mkdir -p #{release_to_link}/public",
- "mkdir -p #{release_to_link}/config",
- "ln -nfs #{c.shared_path}/system #{release_to_link}/public/system",
- "ln -nfs #{c.shared_path}/pids #{release_to_link}/tmp/pids",
- "find #{c.shared_path}/config -type f -exec ln -s {} #{release_to_link}/config \\;",
- "ln -nfs #{c.shared_path}/config/database.yml #{release_to_link}/config/database.yml",
- "ln -nfs #{c.shared_path}/config/mongrel_cluster.yml #{release_to_link}/config/mongrel_cluster.yml",
- ].each do |cmd|
- run cmd
+ info "~> Preparing shared resources for release"
+ symlink_tasks(release_to_link).each do |what, cmd|
+ info "~> #{what}"
+ run(cmd)
end
+ owner = [c.user, c.group].join(':')
+ info "~> Setting ownership to #{owner}"
+ sudo "chown -R #{owner} #{release_to_link}"
+ end
- sudo "chown -R #{c.user}:#{c.group} #{release_to_link}"
- run "if [ -f \"#{c.shared_path}/config/newrelic.yml\" ]; then ln -nfs #{c.shared_path}/config/newrelic.yml #{release_to_link}/config/newrelic.yml; fi"
+ def symlink_tasks(release_to_link)
+ [
+ ["Set group write permissions", "chmod -R g+w #{release_to_link}"],
+ ["Remove revision-tracked shared directories from deployment", "rm -rf #{release_to_link}/log #{release_to_link}/public/system #{release_to_link}/tmp/pids"],
+ ["Create tmp directory", "mkdir -p #{release_to_link}/tmp"],
+ ["Symlink shared log directory", "ln -nfs #{c.shared_path}/log #{release_to_link}/log"],
+ ["Create public directory if needed", "mkdir -p #{release_to_link}/public"],
+ ["Create config directory if needed", "mkdir -p #{release_to_link}/config"],
+ ["Create system directory if needed", "ln -nfs #{c.shared_path}/system #{release_to_link}/public/system"],
+ ["Symlink shared pids directory", "ln -nfs #{c.shared_path}/pids #{release_to_link}/tmp/pids"],
+ ["Symlink other shared config files", "find #{c.shared_path}/config -type f -not -name 'database.yml' -exec ln -s {} #{release_to_link}/config \\;"],
+ ["Symlink mongrel_cluster.yml", "ln -nfs #{c.shared_path}/config/mongrel_cluster.yml #{release_to_link}/config/mongrel_cluster.yml"],
+ ["Symlink database.yml", "ln -nfs #{c.shared_path}/config/database.yml #{release_to_link}/config/database.yml"],
+ ["Symlink newrelic.yml if needed", "if [ -f \"#{c.shared_path}/config/newrelic.yml\" ]; then ln -nfs #{c.shared_path}/config/newrelic.yml #{release_to_link}/config/newrelic.yml; fi"],
+ ]
end
# task
@@ -2,23 +2,40 @@ module EY
module Serverside
module RailsAssetSupport
def compile_assets
+ asset_dir = "#{c.release_path}/app/assets"
+ return unless app_needs_assets?
+ rails_version = bundled_rails_version
roles :app_master, :app, :solo do
- rails_app = "#{c.release_path}/config/application.rb"
- asset_dir = "#{c.release_path}/app/assets"
- if File.exists?(rails_app) && File.directory?(asset_dir)
- return if app_disables_assets?(rails_app)
- if app_builds_own_assets?
- info "~> public/assets already exists, skipping pre-compilation."
- return
- end
- keep_existing_assets
- cmd = "cd #{c.release_path} && PATH=#{c.binstubs_path}:$PATH #{c.framework_envs} rake assets:precompile"
- info "~> Precompiling assets for Rails: #{cmd}"
- run(cmd)
+ keep_existing_assets
+ cmd = "cd #{c.release_path} && PATH=#{c.binstubs_path}:$PATH #{c.framework_envs} rake assets:precompile"
+ if rails_version
+ info "~> Precompiling assets for rails v#{version}"
+ else
+ info "~> [WARN] Precompiling assets even though Rails was not bundled."
end
+ run(cmd)
end
end
+ def app_needs_assets?
+ app_rb_path = File.join(c.release_path, 'config', 'application.rb')
+ return unless File.readable?(app_rb_path) # Not a Rails app in the first place.
+ return unless File.directory?(File.join(c.release_path, 'app', 'assets'))
+ if app_builds_own_assets?
+ info "~> public/assets already exists, skipping pre-compilation."
+ return
+ end
+ if app_disables_assets?(app_rb_path)
+ info "~> application.rb has disabled asset compilation. Skipping."
+ return
+ end
+ unless app_has_asset_task?
+ info "~> No 'assets:precompile' Rake task found. Skipping."
+ return
+ end
+ true
+ end
+
def app_disables_assets?(path)
disabled = nil
File.open(path) do |fd|
@@ -29,6 +46,16 @@ def app_disables_assets?(path)
disabled
end
+ # Runs 'rake -T' to see if there is an assets:precompile task.
+ def app_has_asset_task?
+ # We just run this locally on the app master; everybody else should
+ # have the same code anyway.
+ task_check = "PATH=#{c.binstubs_path}:$PATH #{c.framework_envs} rake -T assets:precompile |grep 'assets:precompile'"
+ cmd = "cd #{c.release_path} && #{task_check}"
+ logged_system "cd #{c.release_path} && #{task_check}"
+ $? == 0
+ end
+
def app_builds_own_assets?
File.directory?(File.join(c.release_path, 'public', 'assets'))
end
@@ -51,7 +78,8 @@ def keep_existing_assets
COMMAND
end
- def bundled_rails_version(lockfile_path)
+ def bundled_rails_version(lockfile_path = nil)
+ lockfile_path ||= File.join(c.release_path, 'Gemfile.lock')
lockfile = File.open(lockfile_path) {|f| f.read}
lockfile.each_line do |line|
# scan for gemname (version) toplevel deps.
@@ -1,6 +1,11 @@
require 'spec_helper'
describe "Deploying an application that uses Bundler" do
+ before(:each) do
+ @bundler_version = ::EY::Serverside::LockfileParser.default_version
+ @version_pattern = Regexp.quote(@bundler_version)
+ end
+
def deploy_test_application
@deploy_dir = File.join(Dir.tmpdir, "serverside-deploy-#{Time.now.to_i}-#{$$}")
@@ -40,11 +45,11 @@ def deploy_test_application
it "runs the right bundler command" do
install_bundler_command_ran = @deployer.commands.detect{ |command| command.index("install_bundler") }
install_bundler_command_ran.should_not be_nil
- install_bundler_command_ran.should == "#{@binpath} install_bundler 1.0.10"
+ install_bundler_command_ran.should include("#{@binpath} install_bundler #{@bundler_version}")
end
it "runs 'bundle install' with --deployment" do
- bundle_install_cmd = @deployer.commands.grep(/bundle _\S+_ install/).first
+ bundle_install_cmd = @deployer.commands.grep(/bundle _#{@version_pattern}_ install/).first
bundle_install_cmd.should_not be_nil
bundle_install_cmd.should include('--deployment')
end
@@ -83,14 +88,15 @@ def deploy_test_application
deploy_test_application
end
- it "default to Bundler 1.0.10" do
+ it "installs the proper Bundler version" do
+ @bundler_version.should == "1.0.10" # Something should break when the default changes.
install_bundler_command_ran = @deployer.commands.detect{ |command| command.index("install_bundler") }
install_bundler_command_ran.should_not be_nil
- install_bundler_command_ran.should == "#{@binpath} install_bundler 1.0.10"
+ install_bundler_command_ran.should include("#{@binpath} install_bundler #{@bundler_version}")
end
it "runs 'bundle install' without --deployment" do
- bundle_install_cmd = @deployer.commands.grep(/bundle _\S+_ install/).first
+ bundle_install_cmd = @deployer.commands.grep(/bundle _#{@version_pattern}_ install/).first
bundle_install_cmd.should_not be_nil
bundle_install_cmd.should_not include('--deployment')
end
@@ -1,8 +1,7 @@
require 'spec_helper'
describe "Deploying a Rails 3.1 application" do
- def deploy_test_application(assets_enabled = true)
- return # pending!
+ def deploy_test_application(assets_enabled = true, &block)
$DISABLE_GEMFILE = false
$DISABLE_LOCKFILE = false
@deploy_dir = File.join(Dir.tmpdir, "serverside-deploy-#{Time.now.to_i}-#{$$}")
@@ -33,8 +32,7 @@ def deploy_test_application(assets_enabled = true)
@binpath = File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'engineyard-serverside'))
@deployer = FullTestDeploy.new(@config)
- yield if block_given?
- @deployer.deploy
+ @deployer.deploy(&block)
end
def prepare_rails31_app(assets_enabled)
@@ -50,15 +48,13 @@ class Application < Rails::Application
File.open(app_rb, 'w') {|f| f.write(app_rb_contents)}
rakefile = File.join(@config.release_path, 'Rakefile')
rakefile_contents = <<-EOF
+desc 'Precompile yar assetz'
task 'assets:precompile' do
sh 'touch precompiled'
end
EOF
File.open(rakefile, 'w') {|f| f.write(rakefile_contents)}
FileUtils.mkdir_p(File.join(@config.release_path, 'app', 'assets'))
-
- @deployer = FullTestDeploy.new(@config)
- @deployer.deploy
end
context "with default production settings" do
@@ -67,7 +63,6 @@ class Application < Rails::Application
end
it "precompiles assets" do
- pending "Bundler is a party"
File.exist?(File.join(@deploy_dir, 'current', 'precompiled')).should be_true
end
end
@@ -78,23 +73,23 @@ class Application < Rails::Application
end
it "does not precompile assets" do
- pending "Bundler is a party"
File.exist?(File.join(@deploy_dir, 'current', 'precompiled')).should be_false
end
end
context "with existing precompilation in a deploy hook" do
before(:all) do
deploy_test_application do
- hook = File.join(@config.release_path, 'deploy', 'before_migrate')
- hook_contents = %Q[system 'touch custom_compiled && mkdir public/assets']
+ deploy_dir = File.join(@config.shared_path, 'cached-copy', 'deploy')
+ FileUtils.mkdir_p(deploy_dir)
+ hook = File.join(deploy_dir, 'before_migrate.rb')
+ hook_contents = %Q[run 'touch custom_compiled && mkdir public/assets']
File.open(hook, 'w') {|f| f.puts(hook_contents) }
File.chmod(0755, hook)
end
end
it "does not replace the public/assets directory" do
- pending "Bundler is a party"
File.exist?(File.join(@deploy_dir, 'current', 'custom_compiled')).should be_true
File.exist?(File.join(@deploy_dir, 'current', 'precompiled')).should be_false
File.directory?(File.join(@deploy_dir, 'current', 'public', 'assets')).should be_true
View
@@ -23,8 +23,12 @@ def info(_) end
def logged_system(cmd)
output = `#{cmd} 2>&1`
successful = ($? == 0)
- if ENV['VERBOSE'] && !successful
- $stderr.puts "\nCommand `#{cmd}` exited with status #{$?.exitstatus}: '#{output.strip}'"
+ if ENV['VERBOSE']
+ if successful
+ $stdout.puts "#{cmd}\n#{output.strip}".chomp
+ else
+ $stderr.puts "\nCommand `#{cmd}` exited with status #{$?.exitstatus}: '#{output.strip}'"
+ end
end
successful
end
@@ -51,10 +51,13 @@ def restart
def bundle
my_env = ENV.to_hash
- ENV.delete("BUNDLE_GEMFILE")
- ENV.delete("BUNDLE_BIN_PATH")
-
- result = super
+ if defined?(Bundler)
+ Bundler.with_clean_env do
+ result = super
+ end
+ else
+ result = super
+ end
ENV.replace(my_env)
result
@@ -65,6 +68,11 @@ def get_bundler_installer(lockfile)
installer.options << ' --quiet' # stfu already!
installer
end
+
+ def deploy
+ yield if block_given?
+ super
+ end
end
module EY::Serverside::Strategies::IntegrationSpec
@@ -78,7 +86,9 @@ def update_repository_cache
%w[bundle compile_assets migrate symlink restart].each do |action|
%w[before after].each do |prefix|
hook = "#{prefix}_#{action}"
- File.open(File.join(deploy_hook_dir, "#{hook}.rb"), 'w') do |f|
+ hook_path = File.join(deploy_hook_dir, "#{hook}.rb")
+ next if File.exist?(hook_path)
+ File.open(hook_path, 'w') do |f|
f.write(%Q{run 'touch "#{c.release_path}/#{hook}.ran"'})
end
end
@@ -99,13 +109,12 @@ def short_log_message(revision)
def gemfile_contents
<<-EOF
-source :gemcutter
-
-gem "bundler", "~> 1.0.0.rc.6"
-gem "rake"
+source 'http://rubygems.org'
+gem 'rake', '= 0.8.7'
EOF
end
+ # Generated using Bundler v1.0.10
def lockfile_contents
<<-EOF
GEM
@@ -117,8 +126,7 @@ def lockfile_contents
ruby
DEPENDENCIES
- bundler (~> 1.0.0.rc.6)
- rake
+ rake (= 0.8.7)
EOF
end

0 comments on commit f770496

Please sign in to comment.