capper 0.1.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.
- data/.document +5 -0
- data/.rvmrc +1 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +28 -0
- data/VERSION +1 -0
- data/capper.gemspec +70 -0
- data/lib/capper.rb +32 -0
- data/lib/capper/bundler.rb +13 -0
- data/lib/capper/git.rb +6 -0
- data/lib/capper/rails.rb +9 -0
- data/lib/capper/rvm.rb +30 -0
- data/lib/capper/templates/unicorn.rb.erb +77 -0
- data/lib/capper/templates/unicorn.sh.erb +55 -0
- data/lib/capper/unicorn.rb +64 -0
- data/lib/capper/utils/templates.rb +64 -0
- data/lib/capper/whenever.rb +58 -0
- metadata +132 -0
data/.document
ADDED
data/.rvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rvm use --create ruby-1.9.2-p180@capper
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: http://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
erubis (2.7.0)
|
|
5
|
+
git (1.2.5)
|
|
6
|
+
jeweler (1.6.4)
|
|
7
|
+
bundler (~> 1.0)
|
|
8
|
+
git (>= 1.2.5)
|
|
9
|
+
rake
|
|
10
|
+
rake (0.9.2)
|
|
11
|
+
rcov (0.9.9)
|
|
12
|
+
shoulda (2.11.3)
|
|
13
|
+
|
|
14
|
+
PLATFORMS
|
|
15
|
+
ruby
|
|
16
|
+
|
|
17
|
+
DEPENDENCIES
|
|
18
|
+
bundler (~> 1.0.0)
|
|
19
|
+
erubis
|
|
20
|
+
jeweler (~> 1.6.4)
|
|
21
|
+
rcov
|
|
22
|
+
shoulda
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2011 Benedikt Böhm
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
= capper
|
|
2
|
+
|
|
3
|
+
Capper is a collection of opinionated Capistrano recipes
|
|
4
|
+
|
|
5
|
+
== Contributing to capper
|
|
6
|
+
|
|
7
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
|
8
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
|
9
|
+
* Fork the project
|
|
10
|
+
* Start a feature/bugfix branch
|
|
11
|
+
* Commit and push until you are happy with your contribution
|
|
12
|
+
|
|
13
|
+
== Copyright
|
|
14
|
+
|
|
15
|
+
Copyright (c) 2011 Benedikt Böhm. See LICENSE.txt for
|
|
16
|
+
further details.
|
|
17
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'bundler'
|
|
5
|
+
|
|
6
|
+
begin
|
|
7
|
+
Bundler.setup(:default, :development)
|
|
8
|
+
rescue Bundler::BundlerError => e
|
|
9
|
+
$stderr.puts e.message
|
|
10
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
|
11
|
+
exit e.status_code
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
require 'rake'
|
|
15
|
+
require 'jeweler'
|
|
16
|
+
|
|
17
|
+
Jeweler::Tasks.new do |gem|
|
|
18
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
|
19
|
+
gem.name = "capper"
|
|
20
|
+
gem.homepage = "http://github.com/hollow/capper"
|
|
21
|
+
gem.license = "MIT"
|
|
22
|
+
gem.summary = %Q{Capistrano extensions for easy deployment}
|
|
23
|
+
gem.description = %Q{Capistrano extensions for easy deployment}
|
|
24
|
+
gem.email = "bb@xnull.de"
|
|
25
|
+
gem.authors = ["Benedikt Böhm"]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Jeweler::RubygemsDotOrgTasks.new
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.0
|
data/capper.gemspec
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Generated by jeweler
|
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
|
4
|
+
# -*- encoding: utf-8 -*-
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |s|
|
|
7
|
+
s.name = %q{capper}
|
|
8
|
+
s.version = "0.1.0"
|
|
9
|
+
|
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
|
+
s.authors = ["Benedikt Böhm"]
|
|
12
|
+
s.date = %q{2011-07-12}
|
|
13
|
+
s.description = %q{Capistrano extensions for easy deployment}
|
|
14
|
+
s.email = %q{bb@xnull.de}
|
|
15
|
+
s.extra_rdoc_files = [
|
|
16
|
+
"LICENSE.txt",
|
|
17
|
+
"README.rdoc"
|
|
18
|
+
]
|
|
19
|
+
s.files = [
|
|
20
|
+
".document",
|
|
21
|
+
".rvmrc",
|
|
22
|
+
"Gemfile",
|
|
23
|
+
"Gemfile.lock",
|
|
24
|
+
"LICENSE.txt",
|
|
25
|
+
"README.rdoc",
|
|
26
|
+
"Rakefile",
|
|
27
|
+
"VERSION",
|
|
28
|
+
"capper.gemspec",
|
|
29
|
+
"lib/capper.rb",
|
|
30
|
+
"lib/capper/bundler.rb",
|
|
31
|
+
"lib/capper/git.rb",
|
|
32
|
+
"lib/capper/rails.rb",
|
|
33
|
+
"lib/capper/rvm.rb",
|
|
34
|
+
"lib/capper/templates/unicorn.rb.erb",
|
|
35
|
+
"lib/capper/templates/unicorn.sh.erb",
|
|
36
|
+
"lib/capper/unicorn.rb",
|
|
37
|
+
"lib/capper/utils/templates.rb",
|
|
38
|
+
"lib/capper/whenever.rb"
|
|
39
|
+
]
|
|
40
|
+
s.homepage = %q{http://github.com/hollow/capper}
|
|
41
|
+
s.licenses = ["MIT"]
|
|
42
|
+
s.require_paths = ["lib"]
|
|
43
|
+
s.rubygems_version = %q{1.6.2}
|
|
44
|
+
s.summary = %q{Capistrano extensions for easy deployment}
|
|
45
|
+
|
|
46
|
+
if s.respond_to? :specification_version then
|
|
47
|
+
s.specification_version = 3
|
|
48
|
+
|
|
49
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
50
|
+
s.add_runtime_dependency(%q<erubis>, [">= 0"])
|
|
51
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
|
52
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
|
53
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
|
54
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
|
55
|
+
else
|
|
56
|
+
s.add_dependency(%q<erubis>, [">= 0"])
|
|
57
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
|
58
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
|
59
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
|
60
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
|
61
|
+
end
|
|
62
|
+
else
|
|
63
|
+
s.add_dependency(%q<erubis>, [">= 0"])
|
|
64
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
|
65
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
|
66
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
|
67
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
data/lib/capper.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'capistrano'
|
|
2
|
+
|
|
3
|
+
unless Capistrano::Configuration.respond_to?(:instance)
|
|
4
|
+
abort "capper requires Capistrano 2"
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require 'capper/utils/templates'
|
|
8
|
+
|
|
9
|
+
# mixin various helpers
|
|
10
|
+
include Capper::Utils::Templates
|
|
11
|
+
|
|
12
|
+
# define a bunch of defaults that make sense
|
|
13
|
+
Capistrano::Configuration.instance(true).load do
|
|
14
|
+
# apps should not require root access
|
|
15
|
+
_cset(:use_sudo, false)
|
|
16
|
+
_cset(:group_writable, false)
|
|
17
|
+
|
|
18
|
+
# default app layout
|
|
19
|
+
_cset(:user) { application }
|
|
20
|
+
_cset(:bin_path) { File.join(deploy_to, "bin") }
|
|
21
|
+
_cset(:base_path) { "/var/app" }
|
|
22
|
+
set(:deploy_to) { "#{base_path}/#{application}" }
|
|
23
|
+
|
|
24
|
+
# cleanup by default
|
|
25
|
+
after "deploy:update", "deploy:cleanup"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class Capper
|
|
29
|
+
def self.load(&block)
|
|
30
|
+
Capistrano::Configuration.instance(true).load(&block)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../capper' unless defined?(Capper)
|
|
2
|
+
require 'bundler/capistrano'
|
|
3
|
+
|
|
4
|
+
Capper.load do
|
|
5
|
+
namespace :bundle do
|
|
6
|
+
desc "Setup bundler"
|
|
7
|
+
task :setup, :except => {:no_release => true} do
|
|
8
|
+
run "if ! gem query -i -n ^bundler$ >/dev/null; then gem install bundler; fi"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
before "bundle:install", "bundle:setup"
|
|
13
|
+
end
|
data/lib/capper/git.rb
ADDED
data/lib/capper/rails.rb
ADDED
data/lib/capper/rvm.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../capper' unless defined?(Capper)
|
|
2
|
+
|
|
3
|
+
$:.unshift(File.expand_path('./lib', ENV['rvm_path']))
|
|
4
|
+
require 'rvm/capistrano'
|
|
5
|
+
|
|
6
|
+
Capper.load do
|
|
7
|
+
set(:rvm_type, :user)
|
|
8
|
+
set(:rvm_ruby_string, File.read(".rvmrc").gsub(/^rvm use --create (.*)@.*/, '\1').strip)
|
|
9
|
+
|
|
10
|
+
namespace :rvm do
|
|
11
|
+
# install the requested ruby if missing
|
|
12
|
+
desc "Install the selected ruby version using RVM."
|
|
13
|
+
task :setup, :except => {:no_release => true} do
|
|
14
|
+
run("if ! rvm list rubies | grep -q #{rvm_ruby_string}; then " +
|
|
15
|
+
"rvm install #{rvm_ruby_string}; fi",
|
|
16
|
+
:shell => "/bin/bash -l")
|
|
17
|
+
|
|
18
|
+
# this ensures that Gentoos declare -x RUBYOPT="-rauto_gem" is ignored.
|
|
19
|
+
run "touch ~/.rvm/rubies/#{rvm_ruby_string}/lib/ruby/site_ruby/auto_gem.rb"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# prevents interactive rvm dialog
|
|
23
|
+
task :untrust_rvmrc, :except => {:no_release => true} do
|
|
24
|
+
run "rvm rvmrc untrust #{current_path}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
on :start, "rvm:setup"
|
|
29
|
+
after "deploy:update_code", "rvm:untrust_rvmrc"
|
|
30
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# -*- ruby -*-
|
|
2
|
+
# Sample verbose configuration file for Unicorn
|
|
3
|
+
#
|
|
4
|
+
# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
|
|
5
|
+
# documentation.
|
|
6
|
+
|
|
7
|
+
# Use at least one worker per core if you're on a dedicated server,
|
|
8
|
+
# more will usually help for _short_ waits on databases/caches.
|
|
9
|
+
worker_processes <%= worker_processes %>
|
|
10
|
+
|
|
11
|
+
# Help ensure your application will always spawn in the symlinked
|
|
12
|
+
# "current" directory that Capistrano sets up.
|
|
13
|
+
working_directory "<%= current_path %>"
|
|
14
|
+
|
|
15
|
+
# listen on Unix domain socket and let nginx proxy
|
|
16
|
+
listen "<%= shared_path %>/pids/unicorn.sock"
|
|
17
|
+
|
|
18
|
+
# nuke workers after 30 seconds instead of 60 seconds (the default)
|
|
19
|
+
timeout 30
|
|
20
|
+
|
|
21
|
+
# Location of the pidfile. Should not be changed unless you
|
|
22
|
+
# know what you are doing.
|
|
23
|
+
pid "<%= shared_path %>/pids/unicorn.pid"
|
|
24
|
+
|
|
25
|
+
# By default, the Unicorn logger will write to stderr.
|
|
26
|
+
# Additionally, some applications/frameworks log to stderr or stdout,
|
|
27
|
+
# so prevent them from going to /dev/null when daemonized here:
|
|
28
|
+
stderr_path "<%= shared_path %>/log/unicorn.stderr.log"
|
|
29
|
+
stdout_path "<%= shared_path %>/log/unicorn.stdout.log"
|
|
30
|
+
|
|
31
|
+
# combine REE with "preload_app true" for memory savings
|
|
32
|
+
# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
|
|
33
|
+
preload_app true
|
|
34
|
+
|
|
35
|
+
if GC.respond_to?(:copy_on_write_friendly=)
|
|
36
|
+
GC.copy_on_write_friendly = true
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# this is required to make bundler use the correct Gemfile in case unicorn is
|
|
40
|
+
# upgraded via USR2. otherwise the symlink will be expanded and old Gemfiles
|
|
41
|
+
# may be used after upgrade.
|
|
42
|
+
before_exec do |server|
|
|
43
|
+
ENV["BUNDLE_GEMFILE"] = "<%= current_path %>/Gemfile"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
before_fork do |server, worker|
|
|
47
|
+
# the following is highly recomended for Rails + "preload_app true"
|
|
48
|
+
# as there's no need for the master process to hold a connection
|
|
49
|
+
defined?(ActiveRecord::Base) and
|
|
50
|
+
ActiveRecord::Base.connection.disconnect!
|
|
51
|
+
|
|
52
|
+
# This allows a new master process to incrementally
|
|
53
|
+
# phase out the old master process with SIGTTOU to avoid a
|
|
54
|
+
# thundering herd (especially in the "preload_app false" case)
|
|
55
|
+
# when doing a transparent upgrade. The last worker spawned
|
|
56
|
+
# will then kill off the old master process with a SIGQUIT.
|
|
57
|
+
old_pid = "<%= shared_path %>/pids/unicorn.pid.oldbin"
|
|
58
|
+
if old_pid != server.pid
|
|
59
|
+
begin
|
|
60
|
+
sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
|
|
61
|
+
Process.kill(sig, File.read(old_pid).to_i)
|
|
62
|
+
rescue Errno::ENOENT, Errno::ESRCH
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
after_fork do |server, worker|
|
|
68
|
+
# the following is *required* for Rails + "preload_app true",
|
|
69
|
+
defined?(ActiveRecord::Base) and
|
|
70
|
+
ActiveRecord::Base.establish_connection
|
|
71
|
+
|
|
72
|
+
# if preload_app is true, then you may also want to check and
|
|
73
|
+
# restart any other shared sockets/descriptors such as Memcached,
|
|
74
|
+
# and Redis. TokyoCabinet file handles are safe to reuse
|
|
75
|
+
# between any number of forked children (assuming your kernel
|
|
76
|
+
# correctly implements pread()/pwrite() system calls)
|
|
77
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
export HOME=<%= deploy_to %>
|
|
3
|
+
source <%= deploy_to %>/.rvm/scripts/rvm
|
|
4
|
+
export RAILS_ENV=<%= rails_env %>
|
|
5
|
+
|
|
6
|
+
PIDFILE=<%= shared_path %>/pids/unicorn.pid
|
|
7
|
+
CONFIG=<%= shared_path %>/config/unicorn.rb
|
|
8
|
+
CMD="bundle exec unicorn -c $CONFIG -E $RAILS_ENV -D config.ru"
|
|
9
|
+
|
|
10
|
+
cd <%= current_path %>
|
|
11
|
+
|
|
12
|
+
sig () {
|
|
13
|
+
test -s "$PIDFILE" && kill -$1 $(<$PIDFILE)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
case $1 in
|
|
17
|
+
start)
|
|
18
|
+
sig 0 && echo >&2 "Already running" && exit 0
|
|
19
|
+
$CMD
|
|
20
|
+
;;
|
|
21
|
+
stop)
|
|
22
|
+
sig QUIT && exit 0
|
|
23
|
+
echo >&2 "Not running"
|
|
24
|
+
;;
|
|
25
|
+
kill)
|
|
26
|
+
sig TERM && exit 0
|
|
27
|
+
echo >&2 "Not running"
|
|
28
|
+
;;
|
|
29
|
+
reload)
|
|
30
|
+
sig HUP && echo reloaded OK && exit 0
|
|
31
|
+
echo >&2 "Couldn't reload, starting '$CMD' instead"
|
|
32
|
+
$CMD
|
|
33
|
+
;;
|
|
34
|
+
upgrade)
|
|
35
|
+
sig USR2 && exit 0
|
|
36
|
+
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
|
|
37
|
+
$CMD
|
|
38
|
+
;;
|
|
39
|
+
addworker)
|
|
40
|
+
sig TTIN && echo added one worker to the pool OK && exit 0
|
|
41
|
+
echo >&2 "Couldn't add worker" && exit 1
|
|
42
|
+
;;
|
|
43
|
+
delworker)
|
|
44
|
+
sig TTOU && echo removed one worker from the pool OK && exit 0
|
|
45
|
+
echo >&2 "Couldn't remove worker" && exit 1
|
|
46
|
+
;;
|
|
47
|
+
logrotate)
|
|
48
|
+
sig USR1 && echo rotated logs OK && exit 0
|
|
49
|
+
echo >&2 "Couldn't rotate logs" && exit 1
|
|
50
|
+
;;
|
|
51
|
+
*)
|
|
52
|
+
echo >&2 "Usage: $0 <start|stop|kill|reload|upgrade|addworker|delworker|logrotate>"
|
|
53
|
+
exit 1
|
|
54
|
+
;;
|
|
55
|
+
esac
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../capper' unless defined?(Capper)
|
|
2
|
+
|
|
3
|
+
# Unicorn capistrano controls.
|
|
4
|
+
# See http://unicorn.bogomips.org/SIGNALS.html for signals that can be sent to unicorn.
|
|
5
|
+
|
|
6
|
+
Capper.load do
|
|
7
|
+
# unicorn configuration variables
|
|
8
|
+
_cset(:unicorn_worker_processes, 4)
|
|
9
|
+
_cset(:unicorn_backlog, 64)
|
|
10
|
+
|
|
11
|
+
# these cannot be overriden
|
|
12
|
+
set(:unicorn_script) { "#{bin_path}/unicorn" }
|
|
13
|
+
set(:unicorn_config) { "#{shared_path}/config/unicorn.rb" }
|
|
14
|
+
set(:unicorn_pidfile) { "#{shared_path}/pids/unicorn.pid" }
|
|
15
|
+
|
|
16
|
+
namespace :deploy do
|
|
17
|
+
desc "Start unicorn"
|
|
18
|
+
task :start, :roles => :app, :except => { :no_release => true } do
|
|
19
|
+
run "#{unicorn_script} start"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
desc "Stop unicorn"
|
|
23
|
+
task :stop, :roles => :app, :except => { :no_release => true } do
|
|
24
|
+
run "#{unicorn_script} stop"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc "Restart unicorn with zero downtime"
|
|
28
|
+
task :restart, :roles => :app, :except => { :no_release => true } do
|
|
29
|
+
run "#{unicorn_script} upgrade"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
namespace :unicorn do
|
|
34
|
+
desc "Generate unicorn configuration files"
|
|
35
|
+
task :setup, :roles => :app, :except => { :no_release => true } do
|
|
36
|
+
upload_template("unicorn.rb", unicorn_config,
|
|
37
|
+
:mode => "0644", :prefix => "unicorn")
|
|
38
|
+
upload_template("unicorn.sh", unicorn_script,
|
|
39
|
+
:mode => "0755", :prefix => "unicorn")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
desc "Kill unicorn (this should only be used if all else fails)"
|
|
43
|
+
task :kill, :roles => :app, :except => { :no_release => true } do
|
|
44
|
+
run "#{unicorn_script} kill"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
desc "Add a new worker to the currently running process"
|
|
48
|
+
task :addworker, :roles => :app, :except => { :no_release => true } do
|
|
49
|
+
run "#{unicorn_script} addworker"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
desc "Remove a worker from the currently running process"
|
|
53
|
+
task :delworker, :roles => :app, :except => { :no_release => true } do
|
|
54
|
+
run "#{unicorn_script} delworker"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
desc "Rotate all logfiles in the currently running process"
|
|
58
|
+
task :logrotate, :roles => :app, :except => { :no_release => true } do
|
|
59
|
+
run "#{unicorn_script} logrotate"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
after "deploy:update_code", "unicorn:setup"
|
|
64
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require "erubis"
|
|
2
|
+
|
|
3
|
+
class Capper
|
|
4
|
+
module Utils
|
|
5
|
+
module Templates
|
|
6
|
+
|
|
7
|
+
# render an erb template from config/deploy/templates to the current
|
|
8
|
+
# server list. this will render and upload templates serially using a
|
|
9
|
+
# server-specific @variables binding. see get_binding for details.
|
|
10
|
+
def upload_template(name, path, options={})
|
|
11
|
+
template = "config/deploy/templates/#{name}.erb"
|
|
12
|
+
|
|
13
|
+
unless File.exist?(template)
|
|
14
|
+
template = File.expand_path("../../templates/#{name}.erb", __FILE__)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
erb = Erubis::Eruby.new(File.open(template).read)
|
|
18
|
+
prefix = options.delete(:prefix)
|
|
19
|
+
|
|
20
|
+
if task = current_task
|
|
21
|
+
servers = find_servers_for_task(task, options)
|
|
22
|
+
else
|
|
23
|
+
servers = find_servers(options)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if servers.empty?
|
|
27
|
+
raise Capistrano::NoMatchingServersError, "no servers matching #{task.options.inspect}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
servers.each do |server|
|
|
31
|
+
result = erb.result(get_binding(prefix, server.host))
|
|
32
|
+
put(result, path, options.merge!(:host => server.host))
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# this allows for server specific variables. example:
|
|
37
|
+
#
|
|
38
|
+
# set :unicorn_worker_processes, {
|
|
39
|
+
# "app1.example.com" => 4,
|
|
40
|
+
# "app2.example.com" => 8,
|
|
41
|
+
# }
|
|
42
|
+
def get_binding(prefix, server)
|
|
43
|
+
b = binding()
|
|
44
|
+
|
|
45
|
+
variables.keys.select do |k|
|
|
46
|
+
k =~ /^#{prefix}_/
|
|
47
|
+
end.each do |k|
|
|
48
|
+
new_k = k.to_s.gsub(/^#{prefix}_/, '')
|
|
49
|
+
new_v = fetch(k)
|
|
50
|
+
|
|
51
|
+
if new_v.kind_of?(Hash)
|
|
52
|
+
eval("set(:#{new_k}, \"#{new_v[server] || new_v["default"]}\")", b)
|
|
53
|
+
else
|
|
54
|
+
eval("set(:#{new_k}, \"#{new_v}\")", b)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
return b
|
|
59
|
+
end
|
|
60
|
+
private :get_binding
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'capper' unless defined?(Capper)
|
|
2
|
+
|
|
3
|
+
# whenever requires bundler
|
|
4
|
+
require 'capper/bundler'
|
|
5
|
+
|
|
6
|
+
Capper.load do
|
|
7
|
+
set(:whenever_command) { "bundle exec whenever" }
|
|
8
|
+
set(:whenever_identifier) { application }
|
|
9
|
+
set(:whenever_environment) { fetch(:rails_env, "production") }
|
|
10
|
+
set(:whenever_update_flags) { "--update-crontab #{whenever_identifier} --set environment=#{whenever_environment}" }
|
|
11
|
+
set(:whenever_clear_flags) { "--clear-crontab #{whenever_identifier}" }
|
|
12
|
+
|
|
13
|
+
# Disable cron jobs at the begining of a deploy.
|
|
14
|
+
after "deploy:update_code", "whenever:clear_crontab"
|
|
15
|
+
# Write the new cron jobs near the end.
|
|
16
|
+
after "deploy:symlink", "whenever:update_crontab"
|
|
17
|
+
# If anything goes wrong, undo.
|
|
18
|
+
after "deploy:rollback", "whenever:update_crontab"
|
|
19
|
+
|
|
20
|
+
namespace :whenever do
|
|
21
|
+
desc <<-DESC
|
|
22
|
+
Update application's crontab entries using Whenever. You can configure \
|
|
23
|
+
the command used to invoke Whenever by setting the :whenever_command \
|
|
24
|
+
variable, which can be used with Bundler to set the command to \
|
|
25
|
+
"bundle exec whenever". You can configure the identifier used by setting \
|
|
26
|
+
the :whenever_identifier variable, which defaults to the same value configured \
|
|
27
|
+
for the :application variable. You can configure the environment by setting \
|
|
28
|
+
the :whenever_environment variable, which defaults to the same value \
|
|
29
|
+
configured for the :rails_env variable which itself defaults to "production". \
|
|
30
|
+
Finally, you can completely override all arguments to the Whenever command \
|
|
31
|
+
by setting the :whenever_update_flags variable.
|
|
32
|
+
DESC
|
|
33
|
+
task :update_crontab do
|
|
34
|
+
on_rollback do
|
|
35
|
+
if previous_release
|
|
36
|
+
run "cd #{previous_release} && #{whenever_command} #{whenever_update_flags}", options
|
|
37
|
+
else
|
|
38
|
+
run "cd #{release_path} && #{whenever_command} #{whenever_clear_flags}", options
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
run "cd #{current_path} && #{whenever_command} #{whenever_update_flags}", options
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
desc <<-DESC
|
|
46
|
+
Clear application's crontab entries using Whenever. You can configure \
|
|
47
|
+
the command used to invoke Whenever by setting the :whenever_command \
|
|
48
|
+
variable, which can be used with Bundler to set the command to \
|
|
49
|
+
"bundle exec whenever". You can configure the identifier used by setting \
|
|
50
|
+
the :whenever_identifier variable, which defaults to the same value configured \
|
|
51
|
+
for the :application variable. Finally, you can completely override all \
|
|
52
|
+
arguments to the Whenever command by setting the :whenever_clear_flags variable.
|
|
53
|
+
DESC
|
|
54
|
+
task :clear_crontab do
|
|
55
|
+
run "cd #{release_path} && #{whenever_command} #{whenever_clear_flags}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: capper
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease:
|
|
5
|
+
version: 0.1.0
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- "Benedikt B\xC3\xB6hm"
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
|
|
13
|
+
date: 2011-07-12 00:00:00 +02:00
|
|
14
|
+
default_executable:
|
|
15
|
+
dependencies:
|
|
16
|
+
- !ruby/object:Gem::Dependency
|
|
17
|
+
name: erubis
|
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
19
|
+
none: false
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">="
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: "0"
|
|
24
|
+
type: :runtime
|
|
25
|
+
prerelease: false
|
|
26
|
+
version_requirements: *id001
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: shoulda
|
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
30
|
+
none: false
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: "0"
|
|
35
|
+
type: :development
|
|
36
|
+
prerelease: false
|
|
37
|
+
version_requirements: *id002
|
|
38
|
+
- !ruby/object:Gem::Dependency
|
|
39
|
+
name: bundler
|
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ~>
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: 1.0.0
|
|
46
|
+
type: :development
|
|
47
|
+
prerelease: false
|
|
48
|
+
version_requirements: *id003
|
|
49
|
+
- !ruby/object:Gem::Dependency
|
|
50
|
+
name: jeweler
|
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
|
52
|
+
none: false
|
|
53
|
+
requirements:
|
|
54
|
+
- - ~>
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: 1.6.4
|
|
57
|
+
type: :development
|
|
58
|
+
prerelease: false
|
|
59
|
+
version_requirements: *id004
|
|
60
|
+
- !ruby/object:Gem::Dependency
|
|
61
|
+
name: rcov
|
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
|
63
|
+
none: false
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: "0"
|
|
68
|
+
type: :development
|
|
69
|
+
prerelease: false
|
|
70
|
+
version_requirements: *id005
|
|
71
|
+
description: Capistrano extensions for easy deployment
|
|
72
|
+
email: bb@xnull.de
|
|
73
|
+
executables: []
|
|
74
|
+
|
|
75
|
+
extensions: []
|
|
76
|
+
|
|
77
|
+
extra_rdoc_files:
|
|
78
|
+
- LICENSE.txt
|
|
79
|
+
- README.rdoc
|
|
80
|
+
files:
|
|
81
|
+
- .document
|
|
82
|
+
- .rvmrc
|
|
83
|
+
- Gemfile
|
|
84
|
+
- Gemfile.lock
|
|
85
|
+
- LICENSE.txt
|
|
86
|
+
- README.rdoc
|
|
87
|
+
- Rakefile
|
|
88
|
+
- VERSION
|
|
89
|
+
- capper.gemspec
|
|
90
|
+
- lib/capper.rb
|
|
91
|
+
- lib/capper/bundler.rb
|
|
92
|
+
- lib/capper/git.rb
|
|
93
|
+
- lib/capper/rails.rb
|
|
94
|
+
- lib/capper/rvm.rb
|
|
95
|
+
- lib/capper/templates/unicorn.rb.erb
|
|
96
|
+
- lib/capper/templates/unicorn.sh.erb
|
|
97
|
+
- lib/capper/unicorn.rb
|
|
98
|
+
- lib/capper/utils/templates.rb
|
|
99
|
+
- lib/capper/whenever.rb
|
|
100
|
+
has_rdoc: true
|
|
101
|
+
homepage: http://github.com/hollow/capper
|
|
102
|
+
licenses:
|
|
103
|
+
- MIT
|
|
104
|
+
post_install_message:
|
|
105
|
+
rdoc_options: []
|
|
106
|
+
|
|
107
|
+
require_paths:
|
|
108
|
+
- lib
|
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
|
+
none: false
|
|
111
|
+
requirements:
|
|
112
|
+
- - ">="
|
|
113
|
+
- !ruby/object:Gem::Version
|
|
114
|
+
hash: 2356379123392142359
|
|
115
|
+
segments:
|
|
116
|
+
- 0
|
|
117
|
+
version: "0"
|
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
|
+
none: false
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: "0"
|
|
124
|
+
requirements: []
|
|
125
|
+
|
|
126
|
+
rubyforge_project:
|
|
127
|
+
rubygems_version: 1.6.2
|
|
128
|
+
signing_key:
|
|
129
|
+
specification_version: 3
|
|
130
|
+
summary: Capistrano extensions for easy deployment
|
|
131
|
+
test_files: []
|
|
132
|
+
|