Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ## Capfile
- # Yes this is mostly copy/paste to get basic SCM/Stragegy extracted from
- # cap w/o standard deployment recipes for web services, etc.
- require 'capistrano/recipes/deploy/scm'
- require 'capistrano/recipes/deploy/strategy'
- require 'yaml'
- def _cset(name, *args, &block)
- unless exists?(name)
- set(name, *args, &block)
- end
- end
- # =========================================================================
- # These variables MUST be set in the client capfiles. If they are not set,
- # the deploy will fail with an error.
- # =========================================================================
- _cset(:application) { abort "Please specify the name of your application, set :application, 'foo'" }
- _cset(:repository) { abort "Please specify the repository that houses your application's code, set :repository, 'foo'" }
- # =========================================================================
- # These variables may be set in the client capfile if their default values
- # are not sufficient.
- # =========================================================================
- _cset :scm, :subversion
- _cset :deploy_via, :checkout
- _cset(:deploy_to) { "/u/apps/#{application}" }
- _cset(:revision) { source.head }
- # =========================================================================
- # These variables should NOT be changed unless you are very confident in
- # what you are doing. Make sure you understand all the implications of your
- # changes if you do decide to muck with these!
- # =========================================================================
- _cset(:source) { Capistrano::Deploy::SCM.new(scm, self) }
- _cset(:real_revision) { source.local.query_revision(revision) { |cmd| with_env("LC_ALL", "C") { `#{cmd}` } } }
- _cset(:strategy) { Capistrano::Deploy::Strategy.new(deploy_via, self) }
- _cset(:release_name) { set :deploy_timestamped, true; Time.now.utc.strftime("%Y%m%d%H%M%S") }
- _cset :version_dir, "releases"
- _cset :shared_dir, "shared"
- _cset :current_dir, "current"
- _cset(:releases_path) { File.join(deploy_to, version_dir) }
- _cset(:shared_path) { File.join(deploy_to, shared_dir) }
- _cset(:current_path) { File.join(deploy_to, current_dir) }
- _cset(:release_path) { File.join(releases_path, release_name) }
- _cset(:releases) { capture("ls -x #{releases_path}").split.sort }
- _cset(:current_release) { File.join(releases_path, releases.last) }
- _cset(:previous_release) { File.join(releases_path, releases[-2]) }
- _cset(:current_revision) { capture("cat #{current_path}/REVISION").chomp }
- _cset(:latest_revision) { capture("cat #{current_release}/REVISION").chomp }
- _cset(:previous_revision) { capture("cat #{previous_release}/REVISION").chomp }
- _cset(:run_method) { fetch(:use_sudo, true) ? :sudo : :run }
- # some tasks, like symlink, need to always point at the latest release, but
- # they can also (occassionally) be called standalone. In the standalone case,
- # the timestamped release_path will be inaccurate, since the directory won't
- # actually exist. This variable lets tasks like symlink work either in the
- # standalone case, or during deployment.
- _cset(:latest_release) { exists?(:deploy_timestamped) ? release_path : current_release }
- # =========================================================================
- # These are helper methods that will be available to your recipes.
- # =========================================================================
- # Auxiliary helper method for the `deploy:check' task. Lets you set up your
- # own dependencies.
- def depend(location, type, *args)
- deps = fetch(:dependencies, {})
- deps[location] ||= {}
- deps[location][type] ||= []
- deps[location][type] << args
- set :dependencies, deps
- end
- # Temporarily sets an environment variable, yields to a block, and restores
- # the value when it is done.
- def with_env(name, value)
- saved, ENV[name] = ENV[name], value
- yield
- ensure
- ENV[name] = saved
- end
- load 'config/deploy'
- ## config/deploy
- # Again this is a hacked up version of ONLY SCM/STRAGEY CAPISTRANO GOODNESS with custom deployment stuff.
- set :application, "aggregator"
- set :repository, "svn://your.site.com/aggregator/trunk"
- set :scm, :subversion
- set :deploy_via, :export
- set :deploy_to, "/var/lib/aggregator"
- set :shared_path, "#{deploy_to}/shared"
- set :current_path, "#{deploy_to}/current"
- set :environment, "production"
- set :user, "deploy"
- set :group, "deploy"
- role :app, "your.aggregator.com"
- # = DEPLOYMENT TASKS ================================================================
- namespace :deploy do
- desc 'Deploys latest (HEAD) version of the aggregator and restarts it cleanly'
- task :default do
- update
- end
- desc <<-DESC
- Copies your project and updates the symlink. It does this in a \
- transaction, so that if either `update_code' or `symlink' fail, all \
- changes made to the remote servers will be rolled back, leaving your \
- system in the same state it was in before `update' was invoked. Usually, \
- you will want to call `deploy' instead of `update', but `update' can be \
- handy if you want to deploy, but not immediately restart your application.
- DESC
- task :update do
- transaction do
- update_code
- symlink
- end
- end
- desc <<-DESC
- Copies your project to the remote servers. This is the first stage \
- of any deployment; moving your updated code and assets to the deployment \
- servers. You will rarely call this task directly, however; instead, you \
- should call the `deploy' task (to do a complete deploy) or the `update' \
- task (if you want to perform the `restart' task separately).
- You will need to make sure you set the :scm variable to the source \
- control software you are using (it defaults to :subversion), and the \
- :deploy_via variable to the strategy you want to use to deploy (it \
- defaults to :checkout).
- DESC
- task :update_code, :except => { :no_release => true } do
- on_rollback { run "rm -rf #{release_path}; true" }
- strategy.deploy!
- finalize_update
- end
- desc <<-DESC
- Copies your project to the remote servers. This is the first stage \
- of any deployment; moving your updated code and assets to the deployment \
- servers. You will rarely call this task directly, however; instead, you \
- should call the `deploy' task (to do a complete deploy) or the `update' \
- task (if you want to perform the `restart' task separately).
- You will need to make sure you set the :scm variable to the source \
- control software you are using (it defaults to :subversion), and the \
- :deploy_via variable to the strategy you want to use to deploy (it \
- defaults to :checkout).
- DESC
- task :update_code, :except => { :no_release => true } do
- on_rollback { run "rm -rf #{release_path}; true" }
- strategy.deploy!
- finalize_update
- end
- desc <<-DESC
- [internal] Touches up the released code. This is called by update_code \
- after the basic deploy finishes. It will then set up symlinks to the shared directories.
- DESC
- task :finalize_update, :except => { :no_release => true } do
- run <<-CMD
- rm -rf #{latest_release}/log #{latest_release}/tmp &&
- ln -s #{shared_path}/log #{latest_release}/log &&
- ln -s #{shared_path}/tmp #{latest_release}/tmp
- CMD
- end
- desc <<-DESC
- Updates the symlink to the most recently deployed version. Capistrano works \
- by putting each new release of your application in its own directory. When \
- you deploy a new version, this task's job is to update the `current' symlink \
- to point at the new version. You will rarely need to call this task \
- directly; instead, use the `deploy' task (which performs a complete \
- deploy, including `restart') or the 'update' task (which does everything \
- except `restart').
- DESC
- task :symlink, :except => { :no_release => true } do
- on_rollback { run "rm -f #{current_path}; ln -s #{previous_release} #{current_path}; true" }
- run "rm -f #{current_path} && ln -s #{latest_release} #{current_path}"
- end
- desc <<-DESC
- Rolls back to the previously deployed version. The `current' symlink will \
- be updated to point at the previously deployed version, and then the \
- current release will be removed from the servers. You'll generally want \
- to call `rollback' instead, as it performs a `restart' as well.
- DESC
- task :rollback_code, :except => { :no_release => true } do
- if releases.length < 2
- abort "could not rollback the code because there is no prior release"
- else
- run "rm #{current_path}; ln -s #{previous_release} #{current_path} && rm -rf #{current_release}"
- end
- end
- desc <<-DESC
- Rolls back to a previous version and restarts. This is handy if you ever \
- discover that you've deployed a lemon; `cap rollback' and you're right \
- back where you were, on the previously deployed version.
- DESC
- task :rollback do
- rollback_code
- restart
- end
- desc <<-DESC
- Clean up old releases. By default, the last 5 releases are kept on each \
- server (though you can change this with the keep_releases variable). All \
- other deployed revisions are removed from the servers. By default, this \
- will use sudo to clean up the old releases, but if sudo is not available \
- for your environment, set the :use_sudo variable to false instead.
- DESC
- task :cleanup, :except => { :no_release => true } do
- count = fetch(:keep_releases, 5).to_i
- if count >= releases.length
- logger.important "no old releases to clean up"
- else
- logger.info "keeping #{count} of #{releases.length} deployed releases"
- directories = (releases - releases.last(count)).map { |release|
- File.join(releases_path, release) }.join(" ")
- invoke_command "rm -rf #{directories}", :via => run_method
- end
- end
- end
- # Some hooks to set things up properly after fresh deploy
- after 'deploy', 'config:localize'
- after 'deploy', 'aggregator:restart'
- after 'deploy', 'deploy:cleanup'
- # = VERSIONING SYSTEM TASKS ====================================================================
- namespace :pending do
- desc <<-DESC
- Displays the `diff' since your last deploy. This is useful if you want \
- to examine what changes are about to be deployed. Note that this might \
- not be supported on all SCM's.
- DESC
- task :diff, :except => { :no_release => true } do
- system(source.local.diff(current_revision))
- end
- desc <<-DESC
- Displays the commits since your last deploy. This is good for a summary \
- of the changes that have occurred since the last deploy. Note that this \
- might not be supported on all SCM's.
- DESC
- task :default, :except => { :no_release => true } do
- from = source.next_revision(current_revision)
- system(source.local.log(from))
- end
- end
- # = AGGREGATOR SPECIFIC TASKS ==================================================================
- namespace :aggregator do
- desc 'Stop running aggregator'
- task :stop do
- run "cd #{current_path} && APP_ENV=#{environment} ./script/schedule stop"
- end
- desc 'Start aggregator'
- task :start do
- run "cd #{current_path} && APP_ENV=#{environment} ./script/schedule start"
- end
- desc 'Restart aggregator'
- task :restart do
- stop
- start
- end
- end
- # = INITAL SETUP TASKS =================================================================
- namespace :init do
- desc 'Create remote deployment structure'
- task :setup, :roles => [:app] do
- sudo "mkdir -p #{deploy_to}"
- sudo "chown #{user}:#{group} #{deploy_to}"
- run "mkdir -p #{shared_path}"
- ['tmp','log','config'].each do |path|
- run "mkdir -p #{shared_path}/#{path}"
- end
- run "mkdir -p #{deploy_to}/releases"
- end
- end
- # = CONFIGURATION TASKS ================================================================
- namespace :config do
- desc "Create or update database configuration"
- task :database do
- set :db_host, Capistrano::CLI.ui.ask("database host: ")
- set :db_user, Capistrano::CLI.ui.ask("database user: ")
- set :db_pass, Capistrano::CLI.password_prompt("database password: ")
- database_configuration = <<-EOF
- production:
- adapter: mysql
- database: #{application}
- host: #{db_host}
- username: #{db_user}
- password: #{db_pass}
- EOF
- run "mkdir -p #{shared_path}/config"
- put database_configuration, "#{shared_path}/config/database.yml"
- end
- desc "Symlink shared configurations to current release"
- task :localize, :roles => [:app] do
- %w[database.yml geokit.yml amazon_s3.yml schedule.yml].each do |f|
- run "ln -nsf #{shared_path}/config/#{f} #{current_path}/config/#{f}"
- end
- end
- end
Add Comment
Please, Sign In to add comment